本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2020年07月31日
统计字数: 4136字
阅读时间: 9分钟阅读
本文链接: https://soulteary.com/2020/07/31/lightweight-and-safe-deployment-solution.html
轻量安全的部署方案
智源大会结束,虽然还是很忙,但是总归有了一些时间,可以开始对之前的文章计划进行补完操作,本篇是第一篇补全,聊聊如何在容器环境下,花比较少的资源,来搞定高质量发布。
这个方案适用于小型团队、个人HomeLab,本文有别于我们当前团队使用的 GitLab Runner 相对比较重的方案,如果你面临的是更大规模的团队协作、项目管理需求和追求更全面的 CI/CD 阶段解耦,可以浏览我之前写的关于 GitLab 的内容。
写在前面
部署属于持续集成中场景的一环,而持续集成中和部署相关有几个步骤必不可少:管理代码、产物部署、产物版本管理。也正是因为有这些清晰的步骤划分,配合其他的措施,比如产物检测、安全检测、健康检查等我们才能够做到高效的秒级部署、多分支、多项目快速迭代。
我个人和团队虽然都使用 GitLab 作为 HomeLab 服务器的代码管理方案,但是这个方案如果放在公有云上,对个人/小团队而言,较多的资源消耗对于个人而言还是一个不能忽视的成本,所以这里需要使用一个轻量的解决方案。
诸如 rsync
、scp
等无版本控制的方式在此忽略,因为我们还是期望有一些简单的版本回滚能力的。
下面聊两种不同的简单使用的方案。
方案一:Git Over SSH
最轻量的安全方案便是使用 SSH Git,对资源的消耗几乎可以忽略不计,Git 官方社区文档中也有对这种方案进行描述: Git on the Server - Setting Up the Server 。
首先在服务器端创建一个空的仓库,这里不一定需要使用 bare
模式进行创建,一般模式也是可以的,比如将仓库创建在 /repo-path/
目录。
考虑到服务端安全问题,我们一般使用 RSA KEY 进行 SSH 交互,可以在 ~/.ssh/config
定义服务器配置,减少在使用过程中的命令复杂度:
Host pub-server
Hostname 123.456.789.000
User user
Port 12345
IdentityFile ~/.ssh/id_rsa_for_server
ControlPath ~/.ssh/pub-%r@%h:%p
ControlPersist yes
TCPKeepAlive yes
Compression yes
ForwardAgent yes
当你将你的 RSA PUBLIC KEY 在目标服务器授权之后,便可以和服务器进行数据交互了:
代码语言:txt复制git clone ssh://pub-server/repo-path/repo-name/ dest-name
Cloning into 'dest-name'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 9 (delta 1), reused 9 (delta 1)
Receiving objects: 100% (9/9), done.
Resolving deltas: 100% (1/1), done.
...
git pull
git commit -m "your message"
git push
...
当然因为没有启动 Git Server 所以,这里的仓库需要提前在服务端创建好,或者将非服务端的内容先进行初始化并同步至服务端。
而触发 CI 命令也很简单,使用 Git Hook 即可。
但是这种方案也有一些小缺陷:
- 必须使用 SSH 协议进行交互,不少场景下使用 SSH 或者公开使用 SSH 并不是一个十分稳定/安全的方案,比如会受到网络设备干扰等、或不使用密钥使用密码等。
- 适合项目不多的场景,项目多了之后,不易管理。
方案二:使用轻量 Git 服务软件
关于 Git 轻量软件的基础搭建使用,之前的文章中有提到过:
使用 Docker 和 Traefik v2 搭建轻量代码仓库(Gitea)、使用 Docker 和 Traefik v1 搭建轻量代码仓库(Gogs) ,感兴趣可以进行了解,接下来我们基于第一款软件继续聊聊。
先给出一份参考配置:
代码语言:txt复制version: '3.6'
services:
gitea:
image: gitea/gitea:1.10.3
container_name: gitea.lab.com
ports:
- 127.0.0.1:22:22
environment:
- USER_UID=1000
- USER_GID=1000
- APP_NAME=Private
- RUN_MODE=prod
- RUN_USER=git
- SSH_DOMAIN=gitea.lab.com
- OFFLINE_MODE=true
- HTTP_PORT=3000
- ROOT_URL=https://gitea.lab.com
- LFS_START_SERVER=false
- DB_TYPE=mysql
- DB_HOST=db
- DB_NAME=gitea
- DB_USER=gitea
- DB_PASSWD=gitea
- DB_CHARSET=utf8
- INSTALL_LOCK=false
- DISABLE_GRAVATAR=true
networks:
- traefik
- gitea
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.giteaweb.middlewares=https-redirect@file"
- "traefik.http.routers.giteaweb.entrypoints=http"
- "traefik.http.routers.giteaweb.rule=Host(`gitea.lab.com`)"
- "traefik.http.routers.giteassl.middlewares=content-compress@file"
- "traefik.http.routers.giteassl.entrypoints=https"
- "traefik.http.routers.giteassl.tls=true"
- "traefik.http.routers.giteassl.rule=Host(`gitea.lab.com`)"
- "traefik.http.services.giteabackend.loadbalancer.server.scheme=http"
- "traefik.http.services.giteabackend.loadbalancer.server.port=3000"
volumes:
# 标准 Linux 系统下使用
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./repositories:/data/git/repositories
- ./data:/data/gitea/
logging:
driver: "json-file"
options:
max-size: "10m"
extra_hosts:
- "gitea.lab.com:127.0.0.1"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:3000 || exit 1"]
interval: 5s
db:
image: mysql:5.7.16
restart: always
networks:
- gitea
expose:
- 3306
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: gitea
MYSQL_DATABASE: gitea
MYSQL_USER: gitea
MYSQL_PASSWORD: gitea
TZ: Asia/Shanghai
volumes:
- ./mysql:/var/lib/mysql
# 标准 Linux 系统下使用
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
healthcheck:
test: ["CMD-SHELL", "/etc/init.d/mysql status"]
interval: 30s
networks:
gitea:
internal: true
traefik:
external: true
这里有几个小技巧:
- 分离应用网络避免不同应用都暴露在相同网络,尤其是公网
- 使用 Traefik 进行服务按需暴露
- 将 SSH 等端口暴露在服务器本地,用于服务器内部其他服务调用,比如部署服务
- 对于非长时间使用的服务,也可以在使用的时候进行启动,非活跃时间进行关闭,这个小技巧后面的文章再展开聊吧
最后
三年前我曾在 GitHub 上开了一个项目,想聊聊HomeLab:soulteary/Home-Network-Note,三年过去了,HomeLab 建设的差不多了,但是过程中的不少文章却永远成为了草稿。今天大会结束了,或许是一个整理的好时机。
--EOF