Gitea实现Docker镜像打包上传全流程
本文主要记录自己这两天使用gitea实现把前后端完成打包,构建镜像,以及上传到镜像仓库中实现多地部署。
前置知识
CICD其实已经有过一篇文章介绍了,所以这里不再赘述。
什么是软件仓库?
软件仓库(Software Repository)是一个集中存储、管理和分发软件及其相关文件(如源代码、二进制文件、文档等)的系统或平台。它类似于一个专门存放软件的“图书馆”或“仓库”,旨在简化软件的获取、安装、更新和维护过程。
例如我们常常使用到的一些jar包,npm包或者docker镜像都可以存储在其中,并提供给他人使用。
而Gitea同样也有对应的Package Registry
用来支持软件仓库的功能。详见gitea文档
我要存储的便是docker镜像,也就是Container
,对于存储这类镜像会有很多选择,包括dockerhub,Harbor,阿里私有镜像仓库等或者干脆自己搭建也可以。各家有各家的优势,我选择gitea仅仅是因为我是在本地部署的,我本人访问可以达到最优速率,体验大大增加。也省去了一些不必要的麻烦。
与他差不多的就是Github Package Registry(也提供免费服务,但是吧,我作为新手,肯定还是现在自己这玩明白了再去别地儿玩)。
docker镜像简单介绍
我本来只是会玩docker,导入各种docker镜像,搭建docker网络,以及配置相关的服务。但其实我从未自己构建过镜像。今天尝试一番,也算是揭开神秘面纱了。docker image
本身就像是一个副本,用于启动各种容器,一个镜像,根据传入的参数不同,启动起来的容器也会有一点小区别。但他的内里没变,大体还是这么个东西在这。
然后构建镜像的话,一般需要完成你的项目后,编写一个相对应的dockerfile
文件,可以直接让ai帮你生成,然后在执行docker build -t <你的镜像名字> .
这条命令指的是,基于你当前的目录,他会自动读取是否有dockerfile文件,有的话,就会根据这个文件和对应的目录生成一个镜像,接着就可以用docker images
查看到了。若要将其导出为一个压缩包也可以通过docker save 镜像id > image.tar
实现相应的功能。或者你如我一般把他推送到一个镜像仓库中,便可以方便的使用了。
正式工作
先随便写一个前后端项目,注意前端要与后端相关联,可以访问到后端。
然后分别编写两者的dockerfile文件
我把我的两个文件示例如下:
前端:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# 构建阶段
FROM node:22 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
# 复制nginx配置
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 5555
CMD ["nginx", "-g", "daemon off;"]后端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15FROM python:3.11-slim
WORKDIR /app
# 安装依赖
RUN pip install --no-cache-dir fastapi==0.115.8 uvicorn[standard]==0.34.3 python-multipart
# 复制代码
COPY . .
# 暴露端口
EXPOSE 5000
# 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "5000"]
其中需要注意的是,你在前端中配置好的
nginx.conf
多半需要代理将访问的api都转发到后端。因此你在编写运行的docker-compose.yml
文件时,要记得后端服务的名字与nginx配置里的名字保持一致,这样就可以将整个前后端项目组合成一个。
接下来就是重头戏,如何通过gitea action
实现自动打包构建和上传。
先构建
.gitea/workflow/docker-build-push.yml
文件,文件名你们自己拟定,要在这个目录下,他就可以正确执行action。展示代码
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
83name: Build and Push Docker Images
on:
push:
branches: [ main, develop ]
tags: [ 'v*' ]
pull_request:
branches: [ main, develop ]
jobs:
build-and-push:
runs-on: ubuntu-latest
strategy:
matrix:
service: [frontend, backend]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整的提交历史用于标签生成
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: gitea.zfxt.top
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
# 为后端服务生成元数据
- name: Extract metadata for backend
if: matrix.service == 'backend'
id: meta-backend
uses: docker/metadata-action@v5
with:
images: gitea.zfxt.top/zfxt/backend
tags: |
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=sha,prefix=,suffix=,enable=true
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# 为前端服务生成元数据
- name: Extract metadata for frontend
if: matrix.service == 'frontend'
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: gitea.zfxt.top/zfxt/frontend
tags: |
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=sha,prefix=,suffix=,enable=true
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# 构建和推送后端镜像
- name: Build and push backend image
if: matrix.service == 'backend'
uses: docker/build-push-action@v6
with:
context: ./backend
file: ./backend/dockerfile
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
# 构建和推送前端镜像
- name: Build and push frontend image
if: matrix.service == 'frontend'
uses: docker/build-push-action@v6
with:
context: ./front
file: ./front/dockerfile
push: true
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}逐段解释
1
2
3
4
5
6on:
push:
branches: [ main, develop ]
tags: [ 'v*' ]
pull_request:
branches: [ main, develop ]作用:定义工作流触发场景
- 分支推送:当代码推送到 main或 develop分支时触发
- 标签推送:当打上 v*格式的版本标签(如 v1.0.0)时触发
- Pull Request:当向 main或 develop分支提交 PR 时触发
1
2
3
4
5
6jobs:
build-and-push:
runs-on: ubuntu-latest
strategy:
matrix:
service: [frontend, backend]作用:定义并行构建任务
- runs-on:使用最新 Ubuntu 环境
- matrix:并行构建
frontend
和backend
两个服务
1
2
3
4- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整提交历史作用:拉取仓库代码
1
2
3
4
5
6- name: Login to Registry
uses: docker/login-action@v3
with:
registry: gitea.zfxt.top
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}作用:登录私有 Docker 仓库
- secrets:需在 GitHub 仓库的 Settings > Action中预先配置
- vars: 同上
1
2
3
4
5
6
7
8
9
10
11
12
13
14- name: Extract metadata for backend
if: matrix.service == 'backend'
id: meta-backend
uses: docker/metadata-action@v5
with:
images: gitea.zfxt.top/zfxt/backend
tags: |
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=sha,prefix=,suffix=,enable=true
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}作用:为后端服务生成多维度镜像标签
标签类型:
- latest:仅主分支构建时添加
- sha:基于提交哈希的唯一标识
- branch/pr:分支/PR 名称
- semver:语义化版本(需项目支持版本管理)
- 原因:提供多种标签便于追踪和管理镜像
1
2
3
4
5
6
7
8
9- name: Build and push backend image
if: matrix.service == 'backend'
uses: docker/build-push-action@v6
with:
context: ./backend
file: ./backend/dockerfile
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}作用:构建后端镜像并推送
- context:Dockerfile 所在目录
- file:Dockerfile 文件名
- tags/labels:复用元数据生成的标签
以上差不多就完成了,但是!我真的遇到好些问题,最后归纳一下,
1 | - name: Set up Docker Buildx |
这个插件!!!用不了,用了就要报EOF的错误,可以说我目前和多平台无缘了。害(我忙活了一天才揪出来这个bug,其他nginx代理,校验方式,gitea历史遗留问题都试过了)。结果发现他这个新版的buildx可能用不了。呜呜呜。难过死我了,
最后总结
上传完成后,可以看到我的软件包界面多了几个可以直接使用的包
差不多也就结束了,主要是那个bug太烦人了。啊啊啊。