docker 安装部署 nginx minio nextjs 及 Github Action 实现 CI CD 自动部署
最近使用 Nextjs 写了个博客网站,顺带接触了一下 Docker,Docker 确实真香。目前网站已正常运行,所以文章内的绝大部分应该是不存在大问题的。
本文篇幅应该略长,主要内容如下:
- 所有容器使用
docker-compose
配置,拒绝过长命令 - 多 Docker 容器(Nginx 和其它容器)之间的网络桥接
- 使用 https + 域名
- Nextjs 开发过程中的部分踩坑(包含 Github OAuth 的踩坑)
- Github Action 实现 CI CD 构建镜像并重启容器等。
本文中出现的域名统一使用 example.com
作为示例,服务器为 CentOS 7
,因为 Docker 命令在不同系统版本中可能不太一样,所以在此说明一下本人的操作环境。
服务器安装 Docker 环境及简单命令介绍
参考地址: https://docs.docker.com/engine/install/centos/
- 进入终端,执行如下命令删除系统中的旧版本 docker:
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
- 设置 docker 镜像源(阿里镜像源)
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 安装 docker 引擎
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
插件的具体功能这里就不废话了,可以直接去问 AI。
输入两次 y 确认即可等待安装成功
Docker 启动配置
- 启动 docker
sudo systemctl start docker
- 检查 docker 是否启动成功,随便运行一个 docker 命令
# 检查 docker 启动的进程
docker ps
- 设置 docker 启动自启
sudo systemctl enable docker
- 设置加速(默认 docker 下载镜像是从 docker hub 下载,设置镜像源)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://hub.rat.dev",
"https://docker.wanpeng.top",
"https://doublezonline.cloud",
"https://docker.mrxn.net",
"https://lynn520.xyz",
"https://ginger20240704.asia",
"https://docker.wget.at",
"https://dislabaiot.xyz",
"https://dockerpull.com",
"https://docker.fxxk.dedyn.io",
"https://dhub.kubesre.xyz",
"https://atomhub.openatom.cn",
"https://docker.m.daocloud.io",
"https://docker.udayun.com",
"https://docker.211678.top",
"https://docker.nju.edu.cn",
"https://mirror.iscas.ac.cn",
"https://docker.xuanyuan.me",
"https://docker.1ms.run"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
镜像操作命令(下载镜像, 熟悉命令的可跳过)
docker search <name>
: 搜索(docker hub)镜像docker pull <name>
: 拉取(docker hub)镜像docker images
: 查看已下载镜像docker rmi <name>
: 删除已有镜像
以 nginx 为例
docker search nginx
docker pull nginx
docker images
docker rmi nginx
容器操作命令(启动容器, 熟悉命令的可跳过)
- docker run : 运行镜像
- docker ps : 查看运行中的容器
- docker ps -a : 查看所有容器(包括已停止的)
- docker stop : 停止容器
- docker start : 启动容器
- docker restart : 重启容器
- docker status : 查看容器状态
- docker logs : 查看容器日志
- docker exec: 进入容器
- docker rm : 删除容器
- dokcer rmi : 删除镜像
如果不理解镜像和容器是什么,就以前端的角度来说,镜像就是你的 npm 包,容器就是你的本地项目
Minio 环境搭建
服务器配置较低的不建议使用 minio 在服务器上做资源存储
- docker pull minio/minio
- 新建
/data/container/minio
目录,并在minio
目录下新建config
(配置文件映射)db
(文件存储映射) 和docker-compose.yml
文件
name: minio
services:
minio:
image: minio/minio
container_name: minio
restart: always
environment:
- TZ=Asia/Shanghai
- MINIO_ROOT_USER=设置登陆账号
- MINIO_ROOT_PASSWORD=设置登陆密码
ports:
- 9000:9000
- 9999:9999
volumes:
- ./db:/data
- ./config:/root/.minio
command: minio server /data --console-address ":9999"
- 启动容器
docker compose up -d
- 可以运行
docker compose logs -f
查看运行日志
此时可以访问 http://ip:9999
,前提是安全组和防火墙放行 9999
端口
Nginx
- docker pull nginx ,如果需要更小化的可以使用 nginx:alpine 版本
- nginx:latest 大小约 200M,nginx:alpine 大小约 50M
新建 /data/container/nginx
文件夹,并在 nginx
目录下新建 docker-compose.yml
文件,写入以下内容
services:
nginx:
image: nginx # 或 nginx:alpine
container_name: nginx # 容器名为 nginx
restart: always
ports:
- 80:80
- 443:443
volumes:
- ./html:/usr/share/nginx/html
- ./logs:/var/log/nginx
# - ./nginx.conf:/etc/nginx/nginx.conf # dcoker 不支持文件挂载
- ./conf.d:/etc/nginx/conf.d # conf.d 文件夹下的 *.conf 会被识别成 nginx 配置文件,便于做不同项目的 nginx 配置区分
- ./default.d:/etc/nginx/default.d
environment:
- TZ=Asia/Shanghai
privileged: true # 解决nginx的文件调用的权限问题
dcoker 只支持挂载文件夹,所以 /etc/nginx/nginx.conf
无法映射本地目录,会报错,需要提前拷贝出来
docker cp 容器id或名称:/etc/nginx/nginx.conf ./nginx.conf
新建 test.conf 配置文件
docker 默认安装的 nginx 是没有配置 80 服务的,所以我们需要去本机的 conf.d
文件夹(映射的就是容器 /etc/nginx/conf.d
)下新建 test.conf
文件,这个 test 随便什么名字都行,写入以下内容,只要是 .conf
结尾能让 nginx 识别到就行。
server {
listen 80;
server_name localhost;
location / {
# 注意,这里必须是容器的目录地址,而非宿主机的本地目录,就算做了映射,也一定是容器的目录地址
root /usr/share/nginx/html;
index index.html;
}
}
由于我们将本地的 ./html
和容器的 /usr/share/nginx/html
做映射,所以直接在 html
文件夹下新建 index.html
,写入点东西,保存,docker restart [容器id或名字]
,访问 ip 地址即可看到 html 内容。
acme 泛域名证书
看这一部分就默认有域名了,如果没域名,我不确定 acme 能否正常使用,建议先去 acme 仓库 看看
- docker pull neilpang/acme.sh
- cd /data/container && mkdir acme
新建 docker-compose.yml
,去阿里云 申请一个子账户,添加权限,勾选权限策略 AliyunDNSFullAccess - 管理云解析(DNS)的权限
,会生成 id
和 Secret
,一定要保存好,仅有一次查看机会
services:
acme-sh:
image: neilpang/acme.sh
container_name: acme
restart: always
command: daemon
environment:
- Ali_Key="你的 AccessKeyId"
- Ali_Secret="你的 AccessKeySecret"
volumes:
- ./acme:/acme.sh
network_mode: host
- 注册邮箱(感觉没什么用):
docker exec acme --register-account -m ccc@xx.xxx
- 注册证书:
docker exec acme --issue --dns dns_ali -d example.com -d *.example.com
- 如果网络执行较慢,第二步可以添加
--server https://acme-v02.api.letsencrypt.org/directory
- 如果网络执行较慢,第二步可以添加
执行成功后,会显示证书的路径,如下所示
[Sun Jan 26 06:27:52 UTC 2025] Your cert is in: /acme.sh/example.com_ecc/example.com.cer
[Sun Jan 26 06:27:52 UTC 2025] Your cert key is in: /acme.sh/example.com_ecc/example.com.key
[Sun Jan 26 06:27:52 UTC 2025] The intermediate CA cert is in: /acme.sh/example.com_ecc/ca.cer
[Sun Jan 26 06:27:52 UTC 2025] And the full-chain cert is in: /acme.sh/example.com_ecc/fullchain.cer
如果没成功,建议删除镜像重新拉取执行命令
注意事项
不同的运营商的 DNS API
不一样,这里使用 阿里云,则是 dns_ali
,如果是其它运营商,请参考 How to use DNS API 来配置 key
*.example.com
这里的*
就代表泛域名
执行完毕命令之后,就可以看到在 acme 目录下,将容器的 acme.sh
文件内容全都映射出来了
定时任务更新证书
安装自动更新脚本
docker exec acme --upgrade --auto-upgrade
在 docker 宿主机添加一条定时任务,让 acme 去检查证书是否过期,即将过期是就会执行脚本自动更新
crontab -e
# 添加以下定时任务
10 0 * * * docker exec acme --cron >> /data/container/acme/acme_cron.log 2>&1
10 1 * * * docker restart [nginx容器名称]
每天零点十分,会检查 acme 证书是否快要过期,若符合,则会自动更新证书,并在 一点十分 重启 nginx 容器
然后 :wq
保存退出
使用 crontab -l
查看定时任务是否添加成功
修改 nginx
在 nginx 的 docker-compose.yml
中添加如下内容,即将 acme 的证书给 nginx 识别,可以使用 https 访问
services:
nginx:
volumes:
- /data/container/acme/acme:/etc/nginx/ssl
然后停止 nginx 容器,重新启动,注意,由于更改是 docker compose,所以必须停止 nginx 容器,然后再使用 docker compose up -d 启动
修改 nginx 配置文件
还是之前的 test.conf
配置文件,将之前最简单的配置删掉,添加以下配置,当访问 80 时重定向到 443 端口
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
# root /usr/share/nginx/html;
ssl_certificate "/etc/nginx/ssl/example.com_ecc/example.com.cer";
ssl_certificate_key "/etc/nginx/ssl/example.com_ecc/example.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
}
注意: ssl_certificate
这里指定的是 example.com.cer
,指向此证书能满足大部分场景的基本使用,但是它不是一个完整的证书链。比如第三方网站访问此域名,可能会因为证书链不完整而出错(我这里遇到 netfily 上访问图片资源一直 502),此时必须指向 fullchain.cer
,这是一个完整证书链
重启 nginx 容器:docker restart [容器名称或id]
此时访问 example.com
应该就可以了,如果还是报不安全,建议去运营商的 ssl 管理后台去上传证书,这里以阿里云为例
- 证书文件 -
example.com.cer
- 证书私钥 -
example.com.key
- 证书链 -
ca.cer
这些文件都是 acme 容器映射到主机的本地目录的,都能找到。
nginx 和 minio 网络桥接
现在 minio 的容器和 nginx 的容器是互不干涉的,但是我有(泛)域名之后,想让 nginx 把这个域名代理到 minio。所以需要将两个容器的网络桥接起来,让两个容器共享网络
创建自定义网络桥接,个人不推荐让容器自动创建网络桥接,会导致管理混乱。
docker network create nginx-network
查看现有的网络桥接列表
docker network ls
删除 docker network rm xxx
修改 minio 的 docker-compose.yml
name: minio
services:
minio:
networks:
- nginx-network
networks:
nginx-network:
external: true
nginx 的 docker-compose.yml
services:
nginx:
networks:
- nginx-network
networks:
nginx-network:
external: true
修改 nginx 的配置文件 test.conf
minio 的可视化 UI 服务,使用 minio.example.com
访问
server {
listen 80;
server_name minio.example.com www.minio.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name minio.example.com www.minio.example.com;
ssl_certificate "/etc/nginx/ssl/example.com_ecc/example.com.cer";
ssl_certificate_key "/etc/nginx/ssl/example.com_ecc/example.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
# http://minio 这是目前 minio 容器的名称,9999 是容器 UI 的运行端口
proxy_pass http://minio:9999;
proxy_set_header Host $http_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;
# WebSocket 支持, minio UI 界面需要
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
minio 的 API 服务转发,使用 img.example.com
访问
server {
listen 80;
server_name img.example.com www.img.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name img.example.com www.img.example.com;
ssl_certificate "/etc/nginx/ssl/example.com_ecc/example.com.cer";
ssl_certificate_key "/etc/nginx/ssl/example.com_ecc/example.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 设置客户端请求体大小限制为50MB,不然图片好像高于 1M 就无法通过代码访问展示
client_max_body_size 50m;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 512k;
# 设置缓存控制头
add_header Cache-Control "public, max-age=2592000";
location / {
proxy_pass http://minio:9000;
proxy_set_header Host $http_host;
}
}
当 minio 和 nginx 共享同一个网络后,在 nginx 做转发时,转发的则是容器名称,因为之前 minio 的 docker-compose
配置写的 container_name: minio
,则容器运行成功后,其名称就是 minio
Nextjs
Nextjs 部署就不能直接像单页一样打个 dist 包扔服务器上了,整体流程就是根据像代码先构建镜像,就类似于 docker pull
拉取镜像一样,创建一个镜像,然后运行容器。
新建一个 Nextjs 项目
Docker 部署 Nextjs 项目
Next 项目根目录添加 .dockerignore
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
编写 Dockerfile 构建镜像
使用 pnpm 来管理项目,因此 Dockerfile 和 Nextjs 官方示例并不一样,来源为 掘金,个人感觉此示例还是比较好的,构建出的镜像大约 200M
# 指定基础镜像版本,确保每次构建都是幂等的
FROM node:20-alpine AS base
FROM base AS builder
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
# Node v16.13 开始支持 corepack 用于管理第三方包管理器
# 锁定包管理器版本,确保 CI 每次构建都是幂等的
# RUN corepack enable && corepack prepare pnpm@latest --activate
# 这里指定了 pnpm 和本地开发的 pnpm 版本一致,防止出现跨版本的 break change
RUN corepack enable && corepack prepare pnpm@9.15.3 --activate
WORKDIR /app
# pnpm fetch does require only lockfile
# 注意还需要复制 `.npmrc`,因为里面可能包含 npm registry 等配置,下载依赖需要用到
# !!! 不存在的文件不要写入 COPY 命令中,不然镜像会构建失败
COPY package.json pnpm-lock.yaml ./
# 推荐使用 pnpm fetch 命令下载依赖到 virtual store,专为 docker 构建优化
# 参考:https://pnpm.io/cli/fetch
RUN pnpm fetch
# 将本地文件复制到构建上下文
COPY . .
# Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED 1
# 基于 virtual store 生成 node_modules && 打包构建
# 此处不需要与 package registry 进行通信,因此依赖安装速度极快
# 注意 PNPM v8.4.0 版本有一个 breaking change
# 当 `node_modules` 存在,运行 `pnpm install` 会出现命令行交互操作,导致 CI 挂掉
# 这里加上 `--force` 参数,关闭命令行交互操作
RUN pnpm install --offline --force && pnpm build
FROM base AS runner
# RUN apk update && apk add --no-cache git
RUN apk add --no-cache curl
# 如果需要是用 TZ 环境变量 实现时区控制,需要安装 tzdata 这个包
# debian 的基础镜像默认情况下已经安装了 tzdata,而 ubuntu 并没有
# RUN apk add --no-cache tzdata
ARG RUNTIME_ENV
ENV RUNTIME_ENV=$RUNTIME_ENV
ENV NODE_ENV production
# Docker 容器不推荐用 root 身份运行
# 这边先建立一个特定的用户和用户组,为它分配必要的权限,使用 USER 切换到这个用户
# 注意,如果不是 root 权限,对于可执行文件,需要修改权限,确保文件可以执行
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# 设置时区
# 在使用 Docker 容器时,系统默认的时区就是 UTC 时间(0 时区),和我们实际需要的北京时间相差八个小时
ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8 TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
# PNPM 有一个全局 store,项目中的 node_modules 实际上是全局 store 的 symlink
# 正常需要从上一阶段同时复制 `node_modules` 和全局 store,这样才能正常运行
# 但是由于 `standalone` 目录里面包含所有运行时依赖,且都是独立目录
# 因此可以直接复制该目录,无需复制全局 store(如果复制还会增加镜像体积)
# 另外运行需要的配置文件、dotfile 也都在 `standalone` 目录里面,无需单独复制
# `standalone` 模式打包,默认包含服务端代码,没有客户端代码
# 因为官方建议通过 CDN 托管,但也可以手动复制 `public`、`.next/static` 目录
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# 注意,`standalone` 目录下已经包含了服务端代码,无需再复制 `.next/server`
# COPY --from=builder /app/.next/server ./.next/server
USER nextjs
# Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1
ENV PORT 3000
# 默认暴露 80 端口
EXPOSE 3000
# 用 standalone 模式打包后,生成的 `standalone/node_modules` 目录下缺少 `.bin` 目录
# 导致无法用 `next` 命令启动项目,但可以用 `node server.js` 启动
# 参考:https://nextjs.org/docs/advanced-features/output-file-tracing
CMD ["node", "server.js"]
Dockerfile 注意事项: 执行 COPY 命令时,COPY 的文件必须存在,否则 COPY 失败会导致镜像构建失败
使用
docker build -t nextjs .
来构建镜像,其中nextjs
就是镜像名,名字随便起只要能和项目的docker-compose
使用的镜像名称保持一致即可。
编写 docker-compose 启动容器
services:
app:
build:
context: .
dockerfile: Dockerfile
image: nextjs # docker build -t nextjs .
container_name: blog
ports:
- 3000:3000
networks:
- nginx-network
networks:
nginx-network:
external: true
nginx-network
就是自定义的网络桥接,之前手动创建了,由于 Nextjs 项目要通过 Nginx 代理,所以必须处于同一个网络桥段下,才能让各容器共享一个网络image: nextjs
这里指定了刚才构建的镜像名为nextjs
的镜像,如果不指定,执行docker compose up -d
时,Nextjs 会自动再依据Dockerfile
重新构建一个镜像container_name: blog
指定容器别名,nginx 代理时可以直接http://blog:3000
即可代理到该容器的运行地址
配置 Nginx 代理
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
# root /usr/share/nginx/html;
ssl_certificate "/etc/nginx/ssl/example.com_ecc/example.com.cer";
ssl_certificate_key "/etc/nginx/ssl/example.com_ecc/example.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
# 注释的是普通 dist 项目所需配置
# root /usr/share/nginx/html;
# try_files $uri $uri/ /index.html;
# index index.html index.htm;
proxy_pass http://blog:3000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
配置完之后,直接重启 nginx 容器即可。
Github Action 实现 CI CD 自动化部署
每次提交完代码,都去服务器上执行一堆命令,尤其是 Nextjs 项目的镜像构建,挺慢的,所以我们可以把流程自动化,但是我的服务器太垃圾了,跑 Jenkins 的话这服务器基本啥也干不了,所以利用 Github Action 这种取巧的方式来实现自动打包部署。
GitHub 需要的配置
使用 ssh 连接服务器,需要 ssh 私钥,但是私钥不能直接写入配置文件,GitHub 提供了相关功能,可以理解为 env
。
点击项目仓库的 Settings -> Secrets and variables -> Actions -> new repository secret,填入 key 和 value,多个 secret 需要多次创建,在 GitHub Action 中访问时以 object 对象格式访问。跟 js 的对象语法类似。key 就是对象 key,value 就是 对应的值。
比如
new repository secret
时添加了 keySSH_PRIVATE_KEY
,那么在 GitHub Action 中访问时,就使用${{ secrets.SSH_PRIVATE_KEY }}
。
生成 SSH
ssh 公私钥在 ~/.ssh
下,可以 cd 到该目录下 ls
查看。
如果只有一个 authorized_keys
,则需要使用 ssh-keygen
生成公私钥对。具体步骤如下
ssh-keygen -t rsa -C "github action"
生成公私钥对- 其中
-C "github action"
类似备注,可以省略
- 其中
- 生成成功后
ls
查看,此时应该有三个文件id_rsa
、id_rsa.pub
、authorized_keys
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
,设置公钥内容为authorized_keys
文件的内容,cat ~/.ssh/id_rsa
将私钥内容添加到 GitHub 仓库的 Secret 中。
编写 Github Action
在项目根目录新建 .github/workflows/deploy.yml
工作流文件
指定 main 分支发生 commit 变动时,会触发 workflow(提前在服务器上拉取一次代码)
name: Deploy Blog
on:
push:
branches: main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Connect server to deploy blog
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
command_timeout: 20m
script: |
cd ${{ secrets.PATH_REMOTE }}
MAX_RETRIES=8
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
echo "▶️ Attempt $((RETRY_COUNT+1))/$MAX_RETRIES: Pulling code..."
if git pull origin main; then
echo "✅ Git pull succeeded"
docker stop blog || true
docker rm blog || true
docker rmi nextjs || true
docker build -t nextjs .
docker compose up -d
exit 0
else
echo "❌ Git pull failed (attempt $((RETRY_COUNT+1))/$MAX_RETRIES)"
((RETRY_COUNT++))
sleep 5
fi
done
echo "🛑 Error: Failed to pull code after $MAX_RETRIES attempts"
exit 1
使用 appleboy/ssh-action
连接远程服务器,连接成功后,执行脚本,即 script
部分。
command_timeout
修改为了 20 分钟,默认是 10 分钟,因为有 git pull 的错误重试机制,很容易超过 10 分钟,纯 Docker 构建都要 5 分钟左右
这部分内容其实很少,简单来说就是以下步骤:
- 拉取 GitHub 仓库的最新代码
- 停止容器,删除容器
- 停止镜像,删除镜像
为什么写了一大堆呢?其实就是 git pull
拉取代码失败后的重试机制,因为众所周知的问题,拉取 github 的代码经常失败(当时傻Ⅹ买了台国内服务器,结果自讨苦吃)
Nextjs 开发及部署的简单踩坑
本地 http 访问 https 图片
http 没法访问 https,目前这里有两种方法
- 在项目的
env
中设置NODE_TLS_REJECT_UNAUTHORIZED=0
绕过证书问题 - 使用 next cli,
next dev --experimental-https
,这个命令在启动项目时生成一份证书临时使用
使用 next-auth 生成环境第三方授权出现 Server Error
环境变量设置 AUTH_TRUST_HOST=true
,具体可查看 next-auth issues
容器部署的 Next 项目 next-auth 无法正确推断 redirect_uri
虽然 next-auth 官方说可以自动推断 redirect_uri,本地确实没问题,但是 Docker 部署后的 Next 项目推断失败(笑死)
出现问题的时候,推断出来的 redirect_uri
是 https//: 容器id:容器端口
,但是这种显然是无法公网访问的,而且和 Github 里配置的路径不一致,所以会出错,那就没办法了,就去 env
里明确一下呗
.env.development
:AUTH_URL=http://localhost:3000/api/auth
.env.production
:AUTH_URL=https://example.com/api/auth
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
2024-02-26 Taro 介绍及快速上手