使用 Docker + DockerCompose 封装 web 应用

这篇文章会介绍如何将后端、前端和网关统统运用 Docker 容器进行作业,并毕竟运用 DockerCompose 进行容器编列。

技能栈

前端

  • React
  • Ant Design

后端

  • Go
  • Irisnginx负载均衡

网关

  • Nginx
  • OpenRhttpclientesty
  • Lua
  • 企业微信

后端构建 api

这儿尽管咱们写了 EXPOSE 4变量类型有哪些182,这个只用在测验的时分,出产环境实际上咱们不会将后端接口端口进行显露,
而是经过容器间的变量的指针其意义是指该变量的网络进行相互拜访,以及毕竟会运用 Nginx 进行转发。

FROM gol接口自动化ang:1.15.5
LABEL maintainer="K8sCat <k8scat@gmail.com>"
EXPOSE 4182
ENV GOPROXY=https://goproxy.cn,direct 
GO111MODULE=on
WORKDIR /go/src/github.com/接口是什么k8scat/contnginx怎样读ainerized-a前端开发pp/api
COPY . .
RUN go mod download && 
go build -o api ma接口是什么in.go && 
chmod +x api
ENTRYPOINT [ "./api" ]

前端构建 web

这儿值得一前端开发需求把握什么技能提的是,由于前端必定会去调用后端接口,并且这个接口地址是依据布置nginx负载均衡战略而改变,
所以这儿咱们运用了 ARG 指令进行设置后端的接口地址,
这样咱们只需求在构建镜像的时分传入 --build-arHTTPg REACT_APP变量与函数_BASE_URL=https:http://192.168.1.1登录//example.com/api 就能够调整后端接口地址前端了,
而不是去改动代码。

还有一点,有朋友必定会发现这儿一同运用到了 EntrypointCMD
这是为了接口的效果能够在作业的前端开发需求把握什么技能时分调整前端的端口,但实际上咱们这儿没必要去调整,由于这儿毕竟也是用 Nginx 进行转发。

FROM node:l接口的效果ts
LABEL maintainer="K8sCat <k8scat@gmail.nginx发动指令com>"
WORKDIR /web
COPY . .
ARG REACT_APP_BASE_URL
RUN npm conf接口的效果ig set registry https:/前端开发/registry.npm.taobao.org && 
npm install &&amNginxp; 
npm run bui变量是什么意思lHTTPd && 
npm install -g serve
ENTRYPOINT [ "serve", "-s", "build" ]
CMD [ "-l", "3214" ]

网关构建 gateway

Nginx 装备

这儿咱们就分别设置了后端和前端的上游,然后变量泵设置 locatio变量泵n 规矩进行转发。

这儿有几个点能够说一下:

  • 经过 set_by_lunginx怎样读a 获取容器的环境变量,毕竟在作业的时分经过设置 environment 设置Nginx这些环境变量,愈加活络
  • server_name 运用到了 $hostname,作业时需求设置容器的nginx负载均衡战略 hostname
  • ssl_certificatessl_certificate_key 不能运用变量设置
  • 加载 gateway.lua 脚本实现企业微信的网关认证
ups前端tream web {
server ca-web:3214;
}
upstream api {
server ca-api:4182;
}
server {
set_by_lua $corp_i变量的界说d 'return ohttp 302s.getenv("CORP_ID")';
set_by_lua $agent_id 'return os.getenv("前端训练组织AGENT_ID")';
set_by_lua $secret 'return os.getenv("SECRET")';
set_by_lua $callback_host 'return os.gehttpclienttenv("CALLBACK_HOST"nginx反向署理)';
set_by_lua $callback_schema 'return os.getenv("CALLBACK_SCHEMA")';
set_by_lua $callback_uri 'return os.getenv("CALLBACK_URI")';
set_by_lua $logout_uri 'return os.getenv("LOGOUT_URI")';
set_by_lua $token_expires 'return os.getenv("TOK前端工程师EN_EXPI前端开发是干什么的RES")';
set_by_lua $use前端工程师_sec变量类型有哪些ure_cookie 'return os.getenv("USE_SECURE_COOKIE")';
listen 443 ssl http2;
server_前端开发是干什么的name $ho前端训练组织stname;
reso变量泵lver 8.8变量是什么意思.8.8;
ssl_certificate /certs/cert.crt;
ssl_certificate_key /cehttpwatchrts/cert.key;
ssl_session_cache shared:SSL前端开发需求学什么:1m变量值;
ssl_session_timeout 5mhttp://192.168.1.1登录;接口crc过错计数
ssl前端开发是干什么的_protocols TLSv1接口英文 TLSv1.1 TLSv1.2;
ssl_ciphers AESGCM:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
lua_ssl_verify_depth 2;
lua_ssl_thttp://192.168.1.1登录rusted_certificate /etc/pk变量值i/tls/certs/ca-b接口自动化undle.crt;
if ($time_iso8601 ~ "^(d{4}nginx发动指令)-(https和http的差异d{2})-(d{2})T(d{2})") {
snginx反向署理et $year $1;
set $month $2;
set $day $3;
}
access_log logs/acchttp 404ess_Nginx$yea接口和抽象类的差异r$m前端学什么onth变量是什么意思$day.log main;
error_log logs/error.log;
access_by_lua_file "/usr/local/openresty/nginx/conf/gateway.lua";
location ^~ /gateway {
root   html;
index  index.html index.htm;
}
loc接口类型ation ^~ /api {
proxy_nginx怎样读pass http://api;
proxy_read_timeout 3600;
proxy_http_version 1.1;
proxy_set_header X_FORWARDED_PROTO https;
proxy_set_header X接口自动化-Real-IP $remote_addr;
proxy_sethttp://www.baidu.com_header X-Forwarded-For $remote_addr;
proxy_set_header X-Fornginx负载均衡战略warded-For $proxy_add_x_forwarded_fohttp 404r;
proxy_set_header Host $host;
proxy_set_he前端学什么ader Connection "";
}
location ^~ / {
proxy_pahttp://192.168.1.1登录ss http://web;
proxy_read_http 404timeout 3600;
proxy_http_version 1.1;
proxy_set_header X_FORWARDED_PROTO https;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
p变量泵roxy_set_header X-Forhttpwatchwarded-For $prohttp 302xy_前端面试题add_变量是什么意思x_forwarded_for;
proxy_set_header Host变量与函数 $host;
proxy_set_变量泵header Connection "";
}
error_page 500 502 503 5前端学什么04 /50x.html;
location = /50x.html {
root html;
}
}
server {
listenginx菜鸟教程n 80;
server_name $hostname;
location / {
rewrite ^/(.*) https://$server_name/$1 redirect;
}
}

Dockerfile

FROM openhttp 302resty/openresty:1.19.3.1-centos
LABEL maintainer=前端"K8sCat <k8scat@gmail.com>"
COPY gateway.conf /etc/ng前端开发需求把握什么技能inx/conf.d/gateway.conf
COPY gateway.lua /usr/local/o前端和后端哪个薪酬高penresty/nhttp 404ginx/conf/gateway.lua
COPY nginx.conf /usr/local/openresty/nginx/confhttp署理/nginx.conf
# Install lua-resty-http
RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-http

Lua 实现依据企业微变量与函数信的网接口是什么关认证

这儿面的一些装备参数都是经过获取 Nginx 设置的变量。

local json = re前端训练组织quire("cjson")
local http = require前端学什么("resty.http")
local uri接口测验 = ngx.var.uri
local uri_args = ngx.req.get_uri_args()
local scheme =前端开发 ngx.var.scheme
local cornginx负载均衡战略p_id = ngx.var.corp_id
local agent_id = ngx.var.agent_id
local secret =nginx装备 ngx.var.变量英文secret
local callbac接口测验k_scheme = ngx.var.c接口allback_scheme or scheme
local c变量与函数allback_host =前端开发需求把握什么技能 ngx.var.callback_变量的界说host
local callback_uri = ngx.var.callback_uri
local use_s前端和后端哪个薪酬高ecure_cookie = nnginx负载均衡战略gx.var.use_secure_cookie == "true" or false
local cal前端lback_ur前端开发需求把握什么技能l = callback_schnginx怎样读eme .. "://" .. ca变量英文llback_host .. callback_uri
local redirect_url = callback_scheme .. "://" .. callback_host .. ngx.var.request_uri
local logout_uri = ngx.var.logout_uri or "/logout"
local token_expires = ngx.var.token_expires or "7200"
token_expires = tonumber(token_expires)
local function request_access_token(code)
local request = http.new()
request:set_timeout(7000)
local rhttp 500es, err = r变量英文equest:request_uri("https://qyapi.weixin.qq.com/cgi-bin/gettoken", {
method = "GET",
query = {
corpid = corp_id,
chttp署理orpsecret = secret,
},
ssl_verify = true,
})
if not res thttp://192.168.1.1登录hen
return nil, (err or "access token r前端开发equest failed: " .. (err or "unknown reason"))变量的指针其意义是指该变量的
end
if res.status ~= 200 then
return nil, "received " .. res.status .. " from https://q变量的指针其意义是指该变量的yapi.weixin.qq.com/cgi-bin/gettoken: " .. res.b前端开发需求学什么onginx负载均衡dy
end
local data = json.decode(res.body)
if data["errcode"] ~= 0 then
return nil, data["enginx发动指令rrmsg"]
else
return data["access_token"]
end
end
local function re前端和后端哪个薪酬高quest_user(access_token, code)
local request = http.new()
request:set_timeout(7000)
local res, err变量 = request:request_uri("https://qyapi.weixin接口crc过错计数.qq.com/cgi-bin/user/getuserinfo", {
method = "GET",
query = {
ahttp 302ccess_token = access变量是什么意思_token,
code = c接口crc过错计数ode,
}前端开发,
ssl_verify = true,变量是什么意思
})nginx菜鸟教程
if not res then
return ni前端开发是干什么的l, "get profile request failed: " .. (err or "unknown reason")
end
if res.statushttpclient ~= 200 then
return nil, "received " .. res.status .. " from https://nginx负载均衡qyapi.weixin.qq.com/cgi-接口的效果bin/user/getuserinfo"
end
local userinfo = jso接口自动化n.decode(res.body)
if userinfo["errcode"] == 0 then
ifhttp://192.168.1.1登录 userinfo["UserId"接口自动化] then
res, err = request:request_uri("https://qyapi.weixin.qq.com/chttps和http的差异gi-bin/user/get", {
method = "GET",
query = {
access_token = access_token,
userid = userinfo["UserId"],
},
ssl_verify = true,
})
if not res then
return nil, "g变量名et user request failed: " .. (err or "unknown reason")
end
if res.status ~= 200 then
return nil, "received " ..接口测验 res.status .. " from https://qyapi.weixin.qq.com/cgi-bin/user/get"
end
local user = json.decode(r变量名的命名规矩es.body)
if user["errcode"] == 0 thnginx反向署理en
return user
else
returnhttp 302 nil, user["errmsg"]
ennginx怎样读d
else
return nil, "Unginx发动指令serId not exists"
end
elhttpclientse
return nil, userinfo["errmsg"]
end
end
local functionnginx重启 is_authorized()
local headers = ngx.req.get_h前端开发需求把握什么技能eaders(nginx发动指令)
loca变量类型有哪些l expires = tonumber(ngx.var.cookie_OauthExpires) or 0
local user_id = ngx.unescape_uri(ngx.var.cookie_OauthUserID or "")
l接口和抽象类的差异ocal token = n前端训练组织gx.var.cookie_OauthAccessToken or ""
if expires == 0 and hea变量与函数ders["Onginx重启authExpires"] then
expires = tonumber(headers["OauthExpires"])
end
if user_id:len() == 0 and headers["OauthUserID"] then
user_变量值id = headers["OauthUserID"]
end
if token:len() == 0 and headers["OauthAccessToken"] then
token = headers["OauthAccessToken"]
end
local expect_toke前端学什么n = callback_host .. usnginx负载均衡战略er_id .. exp接口的效果ires
if token == expect_token and expires then
if expires &gtnginx菜鸟教程; ngx.time() then
return true
else
return false
end接口crc过错计数
else
return false
end
end
local function redirectnginx负载均衡_to_auth()
return ngx.redirect("https://open.work.weihttpclientxin.qq.com/wwopen/sso/qrConnect?" .. ngx.encode_args({
appid = corphttp署理_id,
agentid = agent_id,
red接口irect_uri = callback_url,
stat前端和后端哪个薪酬高e = redirect接口英文_url
}))
end
local function authorize()
if uri ~= callback_uri then
ret前端学什么urn redirect_to_auth()
end
local code = uri_args["code"]
if not code thenhttpwatch
ngx.log(ngx.ERR, "not received code from https://open.work.weixin.qq.com/wwopen/sso/qrC接口类型onnect")
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
local access_token, renginx面试题quest_access_token_err = request_access_token(conginx负载均衡战略de)
if not a接口测验ccessnginx是什么意思_token then
ngx.log(ngx.ERR,nginx菜鸟教程 "got error d变量英文uring access token request: " .变量值. requnginx怎样读est_acce变量的指针其意义是指该变量的ss_token_err)
return n变量值gx.exit(ngxHTTP.HTTP_FORBIDDEN)
end
local user, r前端开发是干什么的equest_user_err = request_user(access_token前端,接口是什么 code)
if not user then
ngx.log(ngx.ERR, "got error during profile request: " .. request_user_err)
return ngx.exit(ngx.HTTP_FORBIDDEN)
end变量的界说
ngx.log(ngx.ERR, "user id: " .. user["httpwatchuserid"])
local expires = ngx接口自动化.time() + tokennginx负载均衡战略_expires
local cookie_tail = "; version=1; path=/; Ma接口和抽象类的差异x-Age=" .. expires
if use_secure_cookie then
cookie_tail = c接口测验ookie_tail .. "; secure"
end
local user_id = user["userid"]
local user_token = callback_host .. user_id .. expires
ngx.header["Set-Cookie"] = {
"OauthUserID=变量泵" .. ngx.escape_uri(user_id) .. cookie_变量的指针其意义是指该变量的tail,
"OauthAccessToken=" .. ngx.前端和后端的差异escape_uri(user_token) .. cookie前端开发需求学什么_HTTPtail,
"OauthExpires=" .. expires .. cook前端训练组织ie_tail,
}
return ngx.redirect(uri_args["state"])
end
local function handle_logout()
if uri == logout_uri then
ngx.header["Set-Cookie"] = "OauthAccessToken==del前端开发需求把握什么技能eted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"
--return ngx.redirect("/")
end
end
handle_logout()
if (not is_authorized()) then
authorize()
end

运用 DockerCompose 进行容器编列

这儿需求讲几个点:

  • 设置前端的 args 能够在前端构建时传入后端接口地址
  • 设置网关的 hostnam变量英文e 能够设置网关容器的 hostname
  • 设置网关的 environment 能够传入相关装备
  • 毕竟作业时只需网关层进行显露端口
version: "3.8"
services:
api:
build: ./api
image: ca-api:latest
container_name: ca-api
web:
build:
context: ./web
args:
REACT_APP_BASE_URL: https://example.com/api
image: ca-web:latest
container_name: ca-web
gateway:
build: ./gateway
image: cnginx装备a-gateway:latest
hostname: examphttp://www.baidu.comle.com
volumes:
- ./gateway/certs/fullchain.pemhttp://192.168.1.1登录:/certs/cert.crt
- ./gateway/certs/privkeynginx负载均衡.pem:/certs/cert.key
ports:
- 80:80
- 443:443
environment:
- CORP_ID=
- AGENT_ID=
- SECRET=
- CALLBACK_HOST=example.com
- CALLBACK_S接口文档CHEMA=https
- CALLBACK_URI=/gateway/oauth_wechat
- LOGOUT_URI=/gateway/oauth_logout
-接口的效果 TOKEN_EXPIRES=7200
- USE_SECURE_COOKIE=true
container_name: ca-gateway

开源代码

  • GitHub
  • Gitee

原文链接:k8sHTTPcat.com/posts/conta…

评论

发表回复