[每周一更]-(第57期):用Docker、Docker-compose部署一个完整的前后端go+vue分离项目
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
文章目录
将公司物理机项目改为容器化部署最终方案是通过容器docker-compose部署使项目可以ip+端口访问再通过物理机nginx代理进行https域名访问。
可能还有更好的方式开一个nginx的容器进行代理但由于跟物理机80,443端口冲突暂时没有采用。
可能目前处理不是最好的方式不过容器化已经运用到项目后续要在不断学习中优化加油 过程中参考很多经验的博主的文章不断成长不断学习
1.参考项目
- 用 Docker 构建一个前后端分离的项目 (go+vue)
- github-gin-vue-blog
- github-compose
- goctl的Ddockerfile
- 一个基于 docker 的 go-zero 本地开发运行环境
- Gin-Vue-Admin文档
- Dockerfile 多阶段构建
- docker-compose 打包部署各种语言开发环境
- docker-compose编排部署多服务Web应用
- 手动在进入容器在Apache中新建一个测试页面
- Compose 模板文件
- docker-compose nginx + ssl配置
- Docker nginx https二级域名无端口访问多个web项目
2.技能点
-
多段构建
- 作用是减少构建时间、减小镜像体积
-
配置、网络与存储关系
-
Dockerfile基础概念
-
nginx代理
以 community_backend 社区项目为例
技术栈
- go 1.18.10
- vue 3.2.13
- redis 5.0
- mysql 5.7
- ecs 2c4g 10M
3.GO的Dockerfile配置
后端的结构如图
community_backend
--configs
--...
--cmd
----main.go
--go.mod
--Dockerfile
服务在 /cmd/main.go 下build 的时候使用命令 go build /cmd/main.go
我们把 Dockerfile 建立在项目的根目录下然后写入以下的文件
Dockerfile
# 使用 golang:alpine作为编译使用的容器, 并且将其命名为build
FROM golang:alpine as build
# FROM golang:1.18.10-alpine as build
# 安装gcc等其他编译工具
# RUN apk add build-base
# --no-cache 选项用于不将软件包的索引缓存到镜像中以减小镜像大小。
# ca-certificates 包是一个包含各种根证书的集合用于验证 HTTPS 连接的证书链的有效性。
# 通过安装该包Docker 镜像将包含一组常见的根证书以便应用程序可以验证和建立安全的 HTTPS 连接。
RUN apk --no-cache add ca-certificates
# 如果在国内用goproxy
# ENV GOPROXY https://goproxy.cn,direct
# ENV GO111MODULE="on"
# 设定一个工作目录
WORKDIR /go/src/community_backend
# 复制当前文件夹下所有文件到工作目录中
COPY . .
# 编译服务端
# RUN go generate && go env && go build -v -gcflags="all=-N -l" -o vc_community ./cmd/*.go
# 配置 golang 环境
RUN go env -w GO111MODULE=on \
&& go env -w GOPROXY=https://goproxy.cn,https://goproxy.io,direct \
&& go mod tidy \
&& go build -v -gcflags="all=-N -l" -o cmd/vc_community ./cmd/*.go
# ===========================================================
# 多阶段构建运行服务端
# 因为是在alpine里构建的, 所以同样使用alpine镜像作为运行的容器
FROM alpine:latest
# 维护者
LABEL MAINTAINER = "ifanaticfire@gmail.com"
# 设定一个工作目录
WORKDIR /go/src/community_backend
# 从上一个容器build中复制所有的代码包含可执行文件到当前的工作目录
# COPY --from=build /go/src/community_backend ./
COPY --from=build /go/src/community_backend/cmd ./cmd
COPY --from=build /go/src/community_backend/configs ./configs
COPY --from=build /go/src/community_backend/storage ./storage
# 暴露端口
EXPOSE 8083
# 启动服务端
#ENTRYPOINT ./cmd/vc_community --env=./cmd/env.toml
CMD cd cmd && ./vc_community
先手动docker调试服务是否可以启动
cd community_backend
// 构建镜像, community-backend 为镜像名字
docker build -t community-backend:v0.1 .
// 运行
docker run -it -p "8083:8083" --rm community-backend:v0.1
报错
- returned a non-zero code: 2
- 编译时缺少gcc组件
- 外网ip+端口无法访问后端容器服务
- 配置文件中监听方式由127.0.0.18083 改为 0.0.0.0:8083
4.Vue的Dockerfile配置
前端的结构如图
community-Frontend
--src
--vue.config.js
--nginx_docker.conf
--public
--package.json
--Dockerfile
nginx_docker.conf
server {
listen 8084;
server_name _;
client_max_body_size 50M;
#listen 443 ssl;
#server_name community.humengxu.com;
#ssl_certificate /etc/nginx/ssl/fullchain.cer;
#ssl_certificate_key /etc/nginx/ssl/humengxu.com.key;
#ssl_session_timeout 5m;
# 指定SSL服务器端支持的协议版本
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
# ssl_ciphers ALL!ADH!EXPORT56RC4+RSA+HIGH+MEDIUM+LOW+SSLv2+EXP; 指定加密算法
#ssl_ciphers HIGH:!aNULL:!MD5;
# 在使用SSLv3和TLS协议时指定服务器的加密算法要优先于客户端的加密算法
#ssl_prefer_server_ciphers on;
location /v1/ {
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $http_x_real_ip; #$remote_addr;
proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://177.7.0.11:8083/v1/;
#设置允许跨域
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "POST, GET, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
add_header Access-Control-Allow-Credentials true;
}
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html last;
# proxy_pass http://localhost:8084;
}
}
#配置转发
#server {
# listen 80;
# server_name community.humengxu.com;
#
# return 301 https://$server_name$request_uri;
#}
Dockerfile
# 声明镜像来源为node:16.14.2命名为build
FROM node:16.14.2 as build
# 声明工作目录
WORKDIR /community_frontend/
# 拷贝整个前端项目到当前工作目录
COPY . .
# 通过npm下载cnpm
RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
# 使用cnpm进行安装依赖
RUN cnpm install || npm install
# 安装所有的依赖
RUN npm install
# 打包项目生成的文件保存在./dist下
RUN npm run build
# ===========================================================
# 多阶段构建
#使用nginx
FROM nginx:alpine
LABEL MAINTAINER = "ifanaticfire@gmail.com"
# 暴露8084端口
EXPOSE 8084
EXPOSE 8085
# 复制打包好的文件到nginx的www目录下
COPY --from=build /community_frontend/dist /usr/share/nginx/html
# 把nginx的默认配置改成我们自己的
COPY --from=build /community_frontend/nginx_docker.conf /etc/nginx/conf.d/default.conf
构建
cd community_frontend
// 构建镜像, backend 为镜像名字
docker build -t community-frontend:v0.1 .
// 运行--rm 在容器停止后自动删除容器
# docker run -it -p "8084:8084" --rm community-frontend:v0.1
5.docker-compose 整合前后端
项目结构
-- community_backend
-- community_frontend
-- docker-compose.yaml
关联的mysql和redis都采用云服务如没有则需要单独构建mysql容器和redis容器提供服务这里不做单独容器操作。
我们有两个 service分别是 frontendbackend
在每个 services 里我们通过 networks 选项给每个容器分配了一个网络以及对应的 ip 地址。
比如 backend 就分配到了 177.7.0.11这就是前端的nginx配置的地址。
同时frontend 依赖 backend这样可以让容器按顺序 (backend-frontend) 启动以此来避免不必要的错误。
docker-compose代码片段创建了一个名为 clinicalapi 的自定义网络并指定了 IP 地址管理的配置。其中使用默认的 IPAM 驱动程序并为网络分配了 177.7.0.0/16 的子网。这样容器可以在该网络中分配 IP 地址并可以通过该网络进行通信。
docker-compose.yml
version: "3"
networks:
clinicalapi:
ipam:
driver: default
config:
- subnet: '177.7.0.0/16'
services:
frontend:
build:
context: ./community_frontend
dockerfile: ./Dockerfile
container_name: community-frontend
restart: always
ports:
- '8084:8084'
# - '80:80'
# - '443:443'
#volumes:
# - /usr/local/nginx/conf/ssl/humengxu.com:/etc/nginx/ssl
depends_on:
- backend
command: [ 'nginx-debug', '-g', 'daemon off;' ]
networks:
clinicalapi:
ipv4_address: 177.7.0.10
backend:
build:
context: ./community_backend
dockerfile: ./Dockerfile
container_name: community-backend
restart: always
ports:
- '8083:8083'
networks:
clinicalapi:
ipv4_address: 177.7.0.11
完成 docker-compose.yaml 的编写后就可以尝试运行了
// 强制重写build
docker-compose up --build
// 直接运行
docker-compose up
// 后台运行
docker-compose up -d
错误记录
- 1.容器名称中不能含有除
[a-zA-Z0-9][a-zA-Z0-9_.-]
之外的内容我上线容器采用了_需要修改 - 2.当docker-compose.yml目录换了位置就报错
[+] Running 0/0
⠿ Network community_clinicalapi Error 0.0s
failed to create network community_clinicalapi: Error response from daemon: Pool overlaps with other one on this address space
解决由于更换了目录启动docker-compose.yml存在网卡冲突的情况需要删除网卡和对应网卡的容器即可如下删除clinical_clinicalapi的网卡
```
docker network ls # 查看docker网卡
docker network inspect <网卡id> # 查看具体信息找到与subnet冲突的是哪个
docker network rm <网卡id> # 删除冲突的网卡
docker network ls
NETWORK ID NAME DRIVER SCOPE
3b95a7847c0f bridge bridge local
da49214cfad9 chatgpt_default bridge local
e084524662f9 clinical_clinicalapi bridge local
851e84525446 docker-compose_default bridge local
836d22ebeff8 gitlab_default bridge local
20e8d6149527 host host local
0c37e84ee02c ifanaticfire_default bridge local
74099f10338f none null local
```
以上均是由步骤总结
从git clone 代码仓库 -> 通过Dockerfile打镜像跑容器-> 再通过docker-compose整合前后端容器并运行
按照如上部署已经完整的将go+vue项目部署到容器中国不过还有如下问题
- 1目前配置是走ip+端口形式需要改为域名形式访问并且要追加ssl证书原来物理机就是这么访问的所以目前容器化还需要改造
- 2没有存储镜像仓库而是由代码直接打镜像运行不利于维护
1ip+端口改为https域名访问
第一种通过挂载ssl证书文件增加端口解决当然可以解决但是我得物理机现在有80443端口造成了冲突这种方式我直接进入到容器内是可以访问https域名地址的
通过 -v 挂载证书通过-p 映射端口也是可以的存在docker中有多个nginx的情况就代理转发一下 参考地址Docker多nginx方案https://juejin.cn/post/6847902222760558599#heading-11
docker run -it -p 443:443 -p 80:80 -v /usr/local/nginx/conf/ssl/humengxu.com:/etc/nginx/ssl --rm community-frontend:v0.1
第二种直接在物理机的nginx因为配置了多域名访问多虚拟主机操作直接代理转发同时配置ssl证书也可以正常访问只是这种是容器+物理机nginx转发操作。
虚拟主机的配置用于在一台服务器上托管多个网站或应用程序。
虚拟主机允许通过同一个IP地址和端口来访问多个域名或应用程序并根据请求的域名或其他条件来将请求路由到相应的网站或应用程序。
- 在Apache中虚拟主机的配置通常是通过在配置文件如httpd.conf或apache2.conf中添加VirtualHost块来实现。每个VirtualHost块对应一个虚拟主机的配置其中包含了该虚拟主机的域名、目录路径、日志文件路径等相关信息。可以根据需要添加多个VirtualHost块每个块对应一个虚拟主机。
- 在Nginx中虚拟主机的配置通过server块来实现。每个server块对应一个虚拟主机的配置其中包含了该虚拟主机的域名、目录路径、日志文件路径等相关信息。可以根据需要添加多个server块每个块对应一个虚拟主机。
communit_frontend.conf
server
{
listen 443 ssl;
server_name community.humengxu.com;
ssl_certificate /usr/local/nginx/conf/ssl/humengxu.com/fullchain.cer;
ssl_certificate_key /usr/local/nginx/conf/ssl/humengxu.com/humengxu.com.key;
ssl_session_timeout 5m;
# 指定SSL服务器端支持的协议版本
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
# ssl_ciphers ALL!ADH!EXPORT56RC4+RSA+HIGH+MEDIUM+LOW+SSLv2+EXP; 指定加密算法
ssl_ciphers HIGH:!aNULL:!MD5;
# 在使用SSLv3和TLS协议时指定服务器的加密算法要优先于客户端的加密算法
ssl_prefer_server_ciphers on;
location /v1/ {
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $http_x_real_ip; #$remote_addr;
proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
proxy_pass https://community-api.varclear.com/v1/;
#设置允许跨域
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "POST, GET, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
add_header Access-Control-Allow-Credentials true;
}
location / {
proxy_redirect off;
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_pass http://1.14.34.33:8084/;
}
}
# 配置转发
server {
listen 80;
server_name community.humengxu.com;
# return 301 https://$server_name$request_uri;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
2镜像仓库解决方案
制作前端和后端的镜像然后把制作好的镜像发布
推送默认的dockerhub仓库中当然可以自建仓库用阿里云oss等都行
将docker-compose打包的镜像改名字上传仓库
推送后端镜像
docker tag clinical-backend:latest firehmx/clinical-backend:v0.1
docker push firehmx/clinical-backend:v0.1
推送前端镜像
docker tag clinical-frontend:latest firehmx/clinical-frontend:v0.1
docker push firehmx/clinical-frontend:v0.1
接着修改 docker-compose.yml把 build 参数改为 image填上我们自己的镜像名字就行了。
services:
frontend:
build:
context: ./community_backend
dockerfile: ./Dockerfile
...
改为
frontend:
image: firehmx/clinical-frontend:v0.1
...
backend:
build:
context: ./community_backend
dockerfile: ./Dockerfile
...
改为
backend:
image: firehmx/clinical-backend:v0.1
...
配置好docker-compose.yml然后用 docker-compose up 就可以运行这整一个前后端分离项目
6.Docker清理缓存操作
- 参考地址https://docs.docker.com/engine/reference/commandline/builder_prune/
- 在构建测试的过程中由于是自家小服务器资源紧张发现磁盘一直爆满删除一些大镜像还是会占满的情况就想到是不是也是缓存问题。
经过查询确实是build过程中的缓存启发的占用问题。
因此引出以下知识点如何清除docker的构建过程中的缓存
Docker 18.09 引入了 BuildKit 提升了构建过程的性能、安全、存储管理等能力。
docker system df 命令类似于 Linux上的 df 命令用于查看 Docker 的磁盘使用情况
TYPE 列出了 Docker 使用磁盘的 4 种类型
类型 | 说明 |
---|---|
Images | 所有镜像占用的空间包括拉取下来的镜像和本地构建的。 |
Containers | 运行的容器占用的空间表示每个容器的读写层的空间。 |
Local Volumes | 容器挂载本地数据卷的空间。 |
Build Cache | 镜像构建过程中产生的缓存空间只有在使用 BuildKit 时才有Docker 18.09 以后可用。 |
没清理前
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 46 18 8.928GB 6.253GB (70%)
Containers 29 6 1.779GB 1.779GB (99%)
Local Volumes 5 5 759.8MB 0B (0%)
Build Cache 176 0 5.59GB 5.59GB
清理后
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 46 18 8.928GB 6.253GB (70%)
Containers 29 6 1.779GB 1.779GB (99%)
Local Volumes 5 5 759.8MB 0B (0%)
Build Cache 111 0 0B 0B
一键清理 Build Cache 缓存命令
docker builder prune
如果你希望保留最近一定时间的缓存删除时长更久的缓存可以通过添加 --filter 参数实现例如保留最近10天的缓存示例命令如下
docker builder prune --filter 'until=240h'
另外命令 docker system prune 可以用于清理磁盘删除关闭的容器、无用的数据卷和网络以及dangling镜像即无tag的镜像。
添加参数 docker system prune -a 清理得更加彻底可以将没有容器使用Docker镜像都删掉。
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |