目标 采用一套开源组件,实现私有化的 CI/CD
流程
流程
代码仓库 在 Repo 有 Commit 时触发事件,把 代码 推送到 Builder。本文选用 Gitlab。
镜像构建 把代码打包成 Docker image,并推送到 镜像仓库,再通知生产服务器。本文选用 Gitlab CI。
镜像仓库 储存 Docker Image。本文选用 Nexus。
生产服务器 接受通知后去镜像仓库拉取镜像,再删除老的 container,创建新的 container。本文借助 watchtower。
原则
所有组件使用 Docker Compose 部署
所有组件都使用 HTTPS,公网可访问
所有组件使用验证,且使用强密码,未授权用户什么都做不了
本文规范
所有配置都是真实可用的,部分配置项以占位符 ${} 的方式替代,使用时记得替换成自己的值
#EDIT 是需要注意的地方
组件部署后,还需要登进去进行一些操作。但在写文的时候已经忘了,请发挥聪明才智 :)
watchtower 的 Docker-Compose、配置文件 放在 ~/docker-compose/watchtower 下,卷挂载在 ~/docker_volume/watchtower 下。其他组件同理。
占位符 1 2 3 4 5 ${host} - 域名${port} - 端口${ALICLOUD_ACCESS_KEY} ${ALICLOUD_SECRET_KEY}
Traefik Traefik 是一个网关,和 Nginx 比较类似,不过 Traefik 对 Docker 支持好。比如说,我只要 在 watchtower 的 Docker labels 上写好配置,访问 https://watchtower.${host}:${port}
就能自动路由到 watchtower container 的 80 端口上了。
首先做好域名解析,让阿里云域名 *.${host} 解析到自己的机子上。这里用了泛域名。
创建网络docker network create traefik
~/docker-compose/traefik/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 version: "3.9" services: reverse-proxy: image: traefik container_name: traefik ports: - "${port}:${port}" volumes: - /var/run/docker.sock:/var/run/docker.sock - ./traefik.yml:/etc/traefik/traefik.yml - ./dynamic_conf.yml:/root/dynamic_conf.yml - ~/docker_volume/traefik/crt:/root/crt - ~/docker_volume/traefik/log:/root/log restart: unless-stopped networks: - traefik environment: ALICLOUD_ACCESS_KEY: ${ALICLOUD_ACCESS_KEY} ALICLOUD_SECRET_KEY: ${ALICLOUD_SECRET_KEY} networks: traefik: external: true
~/docker-compose/traefik/dynamic_conf.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 http: middlewares: basic-auth: basicAuth: users: - "admin:$2b$12$PASSPASSPASS" routers: dashboard: rule: "Host(`traefik.`)" service: "api@internal" middlewares: - basic-auth services: docker-hub-service: loadBalancer: servers: - url: "http://nexus:8082"
~/docker-compose/traefik/traefik.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 providers: docker: exposedByDefault: false file: filename: /root/dynamic_conf.yml watch: true api: dashboard: true entryPoints: https: address: ":${port}" http: tls: certresolver: myresolver certificatesResolvers: myresolver: acme: dnsChallenge: provider: alidns delayBeforeCheck: 0 storage: /root/crt/acme.json accessLog: filePath: "/root/log/access.log.json" format: "json"
nexus Nexus 是一个开源的私有镜像仓库,部署后需要新建一个 hosted 类型的 Docker 仓库。
8081 端口是 Web,8082 端口是 Docker 仓库 端口。
~/docker-compose/nexus/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 version: "3.9" services: nexus: image: sonatype/nexus3 container_name: nexus restart: unless-stopped ports: - "18081:8081" - "18082:8082" volumes: - ~/docker_volume/nexus:/nexus-data networks: - traefik labels: - "traefik.enable=true" - "traefik.http.routers.nexus.rule=Host(`nexus.${host}`)" - "traefik.http.routers.nexus.tls=true" - "traefik.http.routers.nexus.tls.certresolver=myresolver" - "traefik.http.routers.nexus.tls.domains[0].main=*.${host}" - "traefik.http.routers.dockerhub.service=docker-hub-service@file" - "traefik.http.routers.dockerhub.rule=Host(`dockerhub.${host}`)" - "traefik.http.routers.dockerhub.tls=true" - "traefik.http.routers.dockerhub.tls.certresolver=myresolver" - "traefik.http.routers.dockerhub.tls.domains[0].main=*.${host}" networks: traefik: external: true
gitlab ~/docker-compose/gitlab/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 version: "3.9" services: gitlab: image: 'gitlab/gitlab-ee' container_name: gitlab restart: unless-stopped hostname: 'gitlab.${host}:${port}' environment: GITLAB_OMNIBUS_CONFIG: | external_url 'https://gitlab.${host}:${port}' nginx['listen_https'] = false nginx['listen_port'] = 80 ports: - '18000:80' - '10022:22' volumes: - '~/docker_volume/gitlab/config:/etc/gitlab' - '~/docker_volume/gitlab/logs:/var/log/gitlab' - '~/docker_volume/gitlab/data:/var/opt/gitlab' labels: - "traefik.enable=true" - "traefik.http.routers.gitlab.rule=Host(`gitlab.${host}`)" - "traefik.http.routers.gitlab.tls=true" - "traefik.http.routers.gitlab.tls.certresolver=myresolver" - "traefik.http.routers.gitlab.tls.domains[0].main=*.${host}" - "traefik.http.services.gitlab-gitlab.loadbalancer.server.port=80" networks: - traefik gitlab-runner: image: 'gitlab/gitlab-runner' container_name: gitlab-runner restart: unless-stopped volumes: - '~/docker_volume/gitlab/runner:/etc/gitlab-runner' - '/var/run/docker.sock:/var/run/docker.sock' privileged: true networks: traefik: external: true
1 2 3 docker exec -it gitlab bash gitlab-rake "gitlab:password:reset" docker run --rm -it -v ~/docker_volume/gitlab/runner:/etc/gitlab-runner gitlab/gitlab-runner register
watchtower ~/docker-compose/watchtower/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 version: "3.9" services: watchtower: image: containrrr/watchtower container_name: watchtower restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock - ~/.docker/config.json:/config.json networks: - traefik command: --http-api-update --interval 60 --cleanup --debug environment: - WATCHTOWER_HTTP_API_TOKEN=12345678 labels: - "traefik.enable=true" - "traefik.http.routers.watchtower.rule=Host(`watchtower.${host}`)" - "traefik.http.routers.watchtower.tls=true" - "traefik.http.routers.watchtower.tls.certresolver=myresolver" - "traefik.http.routers.watchtower.tls.domains[0].main=*.${host}" networks: traefik: external: true
Project CI 以 https://github.com/117503445/goframe_learn 为例
./gitlab-ci.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 stages: - build - trigger build-docker-image: image: docker:dind stage: build before_script: - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - | if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then tag="" echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'" else tag=":$CI_COMMIT_REF_SLUG" echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag" fi - docker build -t "$CI_REGISTRY_IMAGE${tag}" -f Dockerfile_dev . - docker push "$CI_REGISTRY_IMAGE${tag}" rules: - if: $CI_COMMIT_BRANCH exists: - Dockerfile_dev watchtower-trigger: image: alpine:3.13 stage: trigger before_script: - "sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories" - "apk --no-cache add curl" script: - 'curl -H "Authorization: Bearer $CI_ZJ_WATCHTOWER_TOKEN" $CI_ZJ_WATCHTOWER_API' rules: - if: $CI_COMMIT_BRANCH exists: - Dockerfile_dev
最后更新时间:2023-02-26 13:32:19