背景
之前一直有一个细胞自动机链接的项目部署在搬瓦工的服务器上。是原始的ubuntu一步一命令部署,早就已经没法维护。加上搬瓦工的服务器一年需要19.9刀,虽然不贵但是毕竟有免费的Oracle服务器了,就打算把细胞自动机迁移到Oracle的服务器上,顺便docker化掉。
要做什么呢
- 新建一个dockerfile文件为正式Node项目的启动服务
- 通过docker-compose.yml组织切分三个启动段:临时Nginx启动服务,证书申请服务,正式Node项目的启动服务。同时准备好两份Nginx文件
- 在Server端拉取Git源码,通过docker-compose启动细胞自动机的部署
部署代码和流程
源码
部署代码
docker-compose.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
| version: '3'
services: temp-web: image: nginx:alpine ports: - "80:80" volumes: - web-root:/var/www/html - ./nginx-init.conf:/etc/nginx/nginx.conf - nginx-cache:/var/cache/nginx networks: - app-network user: "root" entrypoint: sh -c "mkdir -p /var/cache/nginx && chown -R nginx:nginx /var/cache/nginx && nginx -g 'daemon off;'" restart: unless-stopped
certbot: image: certbot/certbot volumes: - certbot-etc:/etc/letsencrypt - web-root:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email ${your_mail} --non-interactive --agree-tos --no-eff-email -d ${your_domain} --staging networks: - app-network
web: build: . ports: - "80:80" - "443:443" volumes: - certbot-etc:/etc/letsencrypt - web-root:/var/www/html - ./nginx.conf:/etc/nginx/nginx.conf networks: - app-network restart: unless-stopped
volumes: web-root: certbot-etc: certbot-var: nginx-cache:
networks: app-network:
|
dockerfile
这个文件是第三阶段的正式Web服务启动的docker
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| FROM node:14-alpine
RUN apk add --no-cache nginx certbot && \ mkdir -p /var/www/html && \ getent group www-data || addgroup -S www-data && \ getent passwd www-data || adduser -S -G www-data -D www-data && \ chown -R www-data:www-data /var/www/html
WORKDIR /app
COPY package*.json ./ RUN npm install && npm install pm2 -g
COPY . .
EXPOSE 80 443
CMD ["sh", "-c", "pm2 start bin/www && nginx -g 'daemon off;'"]
|
nginx-init.conf
这个是临时的申请证书用的nginx文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| worker_processes auto;
events { worker_connections 1024; }
http { server { listen 80; server_name ${your_domain};
location /.well-known/acme-challenge/ { root /var/www/html; }
location / { return 403; } } }
|
nginx.conf
这个是正式的nginx文件
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
| user www-data; worker_processes auto;
events { worker_connections 1024; }
http { server { listen 80; server_name ${your_domain};
location /.well-known/acme-challenge/ { root /var/www/html; }
location / { return 301 https://$host$request_uri; } }
server { listen 443 ssl; server_name ${your_domain};
ssl_certificate /etc/letsencrypt/live/${your_domain}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/${your_domain}/privkey.pem;
location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; } } }
|
部署流程
启动临时服务
启动临时服务,这个服务是为了给certbot提供域名的path校验,/.well-known/acme-challenge/
。这个服务会占用80端口。
1
| docker-compose up -d temp-web
|
certbot证书校验和申请流程
先dry_run一下申请证书的命令,看看证书校验逻辑是否有问题。因为certbot命令加上了--staging
命令,所以运行下面的命令并不会实际申请证书,也为了避免测试的时候出发certbot的下发证书限制(7天内只能申请5次证书)链接
1
| docker-compose up -d certbot
|
这里直接启动certbot是因为dry_run执行后查看一下日志是否有问题docker logs ${certbot_container_id}
。如果运行没有任何的报错,就可以去掉--staging
。
停止临时的certbot并且删除临时的certbot
1 2
| docker stop ${certbot_container_id} docker rm ${certbot_container_id}
|
去除dry_run命令限制
1
| sed -i 's/--staging//' docker-compose.yml
|
去掉--staging
再次运行certbot启动命令,就会申请证书的证书。这里采用执行一次就退出的操作,操作会保留volume中的证书。申请好证书后就不要再操作certbot了,特别是不要运行docker-compose down -v
操作,会将volume中证书一起删掉。
1
| docker-compose run --rm certbot
|
启动正式服务
首先停止临时服务,防止临时服务一直占用着80端口导致正式服务无法启动
1
| docker stop ${temp_web_container_id}
|
启动正式服务,启动后可以看看${web_container_id}正式服务的日志,看看是否无报错成功拉起正式服务,成功拉起会展示pm2的结果。
1
| docker-compose up -d web
|
证书自动更新流程
部署好之后,需要使用cron创建证书自动更新的逻辑。这样就可以免去手工更新证书的步骤。见工程源代码
1
| sh ./scripts/setup_crontab.sh
|
其他问题记录
发现访问出现(failed)net::ERR_CONTENT_LENGTH_MISMATCH
错误。无法加载js资源文件
解决方案,在nginx中加入proxy_buffering off;