在公司实践了不少docker项目,总结了一套docker+nginx部署方案,以防忘记,为后续作参考。
Docker镜像构建
包含nginx配置、Dockerfile编写、Gitlab CI配置
nginx配置
后台项目不涉及服务端,ssr,不需要node环境,直接使用nginx即可,为了方便更改nginx的配置文件,在项目目录下建立一个nginx.conf文件,这里建立在根目录的config目录下
1
|
touch config/nginx.conf
|
1.nginx.conf编写
由于我们部署的项目并不是直接被用户访问到(会经由公司的服务器代理转发或者负载均衡),所以请按以下配置,否则可能会有奇怪的问题(http2问题)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
server {
listen 80;
listen [::]:80;
server_name localhost;
# 开启gzip----------
# 打开gzip
gzip on;
# 设置用于处理请求压缩的缓冲区数量和大小
gzip_buffers 4 16k;
# 当返回内容大于此值时才会使用gzip进行压缩
gzip_min_length 10k;
# 设置gzip压缩级别,数字越大级别越高,但会提高服务器的CPU资源消耗
gzip_comp_level 6;
# 一定要设置!,因为内外网进行了反向代理到该服务上,server之间默认时使用HTTP/1.0协议通信,gzip默认是1.1!!
gzip_http_version 1.0;
# 增加响应头,告诉接收方经过了压缩处理,对于本身不支持gzip压缩的浏览器有用
gzip_vary on;
# 设置需要压缩的类型,不要压缩图片!!压缩图片太消耗CPU资源
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# ------------------------
# 日志--------------------
access_log /var/log/nginx/nginx-access.log main;
error_log /var/log/nginx/nginx-error.log error;
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
# ------------------------
# 后台项目都是单页面应用,只需设置 /
location / {
root /usr/share/nginx/html;
# history路由需要开启,否则刷新页面时nginx无法找到资源
try_files $uri $uri /index.html;
index index.html index.htm;
# 设置浏览器缓存----------
# 默认情况下nginx的响应头中会带有ETag、Last-modified的协商缓存字段,但无强缓存,所以需要自己设置强缓存cache-control(优先使用cahe-control,不要使用expires,max-age单位s)
# 不能设置private,否则不能被服务器缓存
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
add_header Cache-Control "public,max-age=31536000";
}
location ~* \.(?:css|js)$ {
add_header Cache-Control "public,max-age=2592000";
}
# ------------------------
}
# 如果需要代理其他文件目录(如微前端)可以参考如下配置
# location /subapp {
# alias /usr/share/nginx/subapp;
# try_files $uri $uri/ /index.html;
# index index.html index.htm;
# }
}
|
Dockerfile编写
Dockerfile用于定制镜像,Dockerfile概念可参考使用Dockerfile定制镜像
- 在项目根目录建立文件
1
2
3
|
touch Dockerfile # docker build默认使用的配置
touch Dockerfile.dev # 用于区分dev环境,docker build -f Dockerfile.dev运行
touch dockerignore # 用于docker构建上下文时忽略掉.dockerignore里面的文件列表
|
- Dockerfile及Dockerfile.dev编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
FROM node:12-alpine as node
WORKDIR /app
COPY ./package.json ./yarn.lock /app/
# 利用node_modules缓存
RUN yarn
COPY . /app/
# 正式环境打包
RUN yarn build
# alpine是一个精简的docker镜像,具有最少的软件包,但足以运行节点应用程序。
FROM nginx:alpine
ENV TZ="Asia/Shanghai"
# 拷贝dist文件
COPY --from=node /app/dist /usr/share/nginx/html
# 拷贝nginx配置
COPY --from=node /app/config/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
|
- Dockerfile.dev(用于工作时的内网环境)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
FROM node:12-alpine as node
WORKDIR /app
COPY ./package.json ./yarn.lock /app/
# 利用node_modules缓存
RUN yarn
COPY . /app/
# develop环境打包
RUN yarn build-dev
# alpine是一个精简的docker镜像,具有最少的软件包,但足以运行节点应用程序。
FROM nginx:alpine
ENV TZ="Asia/Shanghai"
# 拷贝dist文件
COPY --from=node /app/dist /usr/share/nginx/html
# 拷贝nginx配置
COPY --from=node /app/config/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
|
- dockerignore
dockerignore的配置也可以和.gitignore保持一致,可以排除掉不需要参与打包的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
logs/
npm-debug.log
yarn-error.log
node_modules/
coverage/
dist/
.idea/
run/
.DS_Store
*.sw*
*.un~
.tsbuildinfo
.tsbuildinfo.*
READEME.m
|
- 优化点
原先我们的项目拷贝目录的操作
1
2
3
|
COPY . /app
RUN yarn & yarn build
|
优化后
1
2
3
4
5
6
|
COPY ./package.json ./yarn.lock /app/
# 利用node_modules缓存
RUN yarn
COPY . /app/
RUN yarn build
|
为什么这么做?为了利用node_modules的缓存,如果一开始拷贝整个项目,runner就会认为这一步的文件改变了,就不会去用缓存,如果先拷贝的package.json和yarn.lock未改变,则会使用之前构建的镜象的这一层去使用缓存
-
使用缓存时,yarn命令秒结束
-
未使用缓存时,yarn命令持续安装
改写这一步能节省掉安装依赖的速度,并且不需要在构建时一并放入node_modules,减小了体积
关于打版本号改变了package.json导致无法使用缓存的问题,可以通过脚本拷贝一个不带version的package.json,然后利用缓存
Gitlab CI配置
git push=>触发 CI=>执行gitlab-ci.yml
Gitlab CI的配置需要在项目中编写.gitlab-ci.yml文件和在gitlab仓库设置CI/CD的变量
- .gitlab-ci.yml
在项目根目录创建
内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
image: 这里需要一个基础的系统,如debian
stages:
- build_develop
- build_release
- build_branch
variables:
DOCKER_REGISTRY_DEV: xxx.dev.com # 推送到内网仓库
DOCKER_REGISTRY: xxx.dev.com # 推送到外网仓库
DOCKER_REPO: frontend/xxx # 镜像仓库目录
before_script:
# 输出当前所有环境变量
- env
build_develop:
tags:
- docker # 使用tag为docker的runner触发构建
# execute shell command only git tag operation
only:
- develop # 只有推送 时才触发该job
stage: build_develop
script:
- image=${DOCKER_REGISTRY_DEV}/$DOCKER_REPO:latest
# login to dockerhub
- docker login -u $NCR_DEV_USER -p $NCR_DEV_TOKEN $DOCKER_REGISTRY_DEV
# build docker image
- echo "$ docker build -t $image"
- docker build -f Dockerfile.dev -t $image .
# push docker image
- echo "$ docker push $image"
- docker push $image
# logout dockerhub
- docker logout $DOCKER_REGISTRY_DEV
build_release:
tags:
- docker # 使用tag为docker的runner触发构建
# execute shell command only git tag operation
only:
- tags # 只有推送tag时才触发该job
stage: build_release
script:
# use git tag name as docker build image name
- TAG=${CI_BUILD_TAG} # 默认使用当前推送的tag名作为镜像tag,可修改为下面的commit hash的前六位等
# use current git commit hash as build image name
# - TAG=${CI_BUILD_REF:0:6}
- image=${DOCKER_REGISTRY}/$DOCKER_REPO:latest
- image_with_tag=${DOCKER_REGISTRY}/$DOCKER_REPO:$TAG
# login to dockerhub
- docker login -u $NCR_USER -p $NCR_TOKEN $DOCKER_REGISTRY
# build docker image
- echo "$ docker build -t $image"
- docker build -t $image -t $image_with_tag .
# push docker image
- echo "$ docker push $image"
- docker push $image
# push docker image
- echo "$ docker push $image_with_tag"
- docker push $image_with_tag
# logout dockerhub
- docker logout $DOCKER_REGISTRY
build_branch:
tags:
- docker
except:
- develop
- tags
- master
stage: build_branch
script:
- TAG=`echo ${CI_BUILD_REF_NAME} | tr "/" "-"`
- image=${DOCKER_REGISTRY_DEV}/${DOCKER_REPO}:${TAG
# login to dockerhub
- docker login -u ${NCR_DEV_USER} -p ${NCR_DEV_TOKEN} ${DOCKER_REGISTRY_DEV}
# build docker image
- echo "$ docker build -t ${image}"
- docker build -f Dockerfile.dev -t ${image} .
# push docker image
- echo "$ docker push ${image}"
- docker push ${image}
# logout dockerhub
- docker logout ${DOCKER_REGISTRY_DEV}
|
- 配置gitlab仓库
需配置变量
镜像的部署
初次部署要手动启用一个docker镜像
- 拉取镜像
- 查看镜像id
- 启动容器
1
|
docker run --name 去一个名字 -d -p 82:80 镜像id
|
- 查看容器启动情况,第一个就是刚才启动的容器
参考文献
- docker从入门到实践
- 连前端都看得懂的《Nginx入门指南》
- 一文读懂前端缓存