使用Compose和Github Actions部署Docker容器

31
我正在使用GitHub Actions触发dockerfile的构建,它会将容器上传到GitHub Container Registry。在最后一步中,我通过SSH连接到我的远程DigitalOcean Droplet,并执行一个脚本从GHCR拉取和安装新镜像。对于我而言,这个工作流很好,因为我只在项目中构建了一个单独的容器。现在我需要NGINX除了API,所以我正在使用docker compose。由于目前项目对资源的需求不高,我想将容器保留在单个dropplet上。
“如何使用Github Actions和Docker Compose自动部署到单个VM的DigitalOcean的正确方法是什么?”
我目前知道的选项有:
1. 跳过在GHCR上构建容器并通过ssh获取repo以执行生产compose文件来开始远程构建。 2. 在GHCR上构建每个容器,将生产compose文件复制到远程上,然后从GHCR拉取和安装。
如果您知道更干净或更有效的选项,请告诉我!
不幸的是,我找到了一个参考docker-compose with Github Actions for CI question
“单个容器的GitHub Action”
name: Github Container Registry to DigitalOcean Droplet

on:
  # Trigger the workflow via push on main branch
  push:
    branches:
      - main
    # use only trigger action if the backend folder changed
    paths:
      - "backend/**"
      - ".github/workflows/**"

jobs:
  # Builds a Docker Image and pushes it to Github Container Registry
  push_to_github_container_registry:
    name: Push to GHCR
    runs-on: ubuntu-latest

    # use the backend folder as the default working directory for the job
    defaults:
      run:
        working-directory: ./backend

    steps:
      # Checkout the Repository
      - name: Checking out the repository
        uses: actions/checkout@v2

      # Setting up Docker Builder
      - name: Set up Docker Builder
        uses: docker/setup-buildx-action@v1

      # Set Github Access Token with "write:packages & read:packages" scope for Github Container Registry.
      # Then go to repository setings and add the copied token as a secret called "CR_PAT"
      # https://github.com/settings/tokens/new?scopes=repo,write:packages&description=Github+Container+Registry
      # ! While GHCR is in Beta make sure to enable the feature
      - name: Logging into GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}

      # Push to Github Container Registry
      - name: Pushing Image to Github Container Registry
        uses: docker/build-push-action@v2
        with:
          context: ./backend
          version: latest
          file: backend/dockerfile
          push: true
          tags: ghcr.io/${{ github.repository }}:latest

  # Connect to existing Droplet via SSH and (re)installs add. runs the image
  # ! Ensure you have installed the preconfigured Droplet with Docker
  # ! Ensure you have added SSH Key to the Droplet
  # !   - its easier to add the SSH Keys bevore createing the droplet
  deploy_to_digital_ocean_dropplet:
    name: Deploy to Digital Ocean Droplet
    runs-on: ubuntu-latest
    needs: push_to_github_container_registry

    steps:
      - name: Deploy to Digital Ocean droplet via SSH action
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.PRIVATE_KEY }}
          port: ${{ secrets.PORT }}
          script: |
            # Stop all running Docker Containers
            docker kill $(docker ps -q)

            # Free up space
            docker system prune -a

            # Login to Github Container Registry
            docker login https://ghcr.io -u ${{ github.repository_owner }} -p ${{ secrets.CR_PAT }}

            # Pull the Docker Image 
            docker pull ghcr.io/${{ github.repository }}:latest

            # Run a new container from a new image
            docker run -d -p 80:8080 -p 443:443 -t ghcr.io/${{ github.repository }}:latest

当前Docker-Compose文件

version: "3"

services:
  api:
    build:
      context: ./backend/api
    networks:
      api-network:
        aliases:
          - api-net
  nginx:
    build:
      context: ./backend/nginx
    ports:
      - "80:80"
      - "443:443"
    networks:
      api-network:
        aliases:
          - nginx-net
    depends_on:
      - api

networks:
  api-network:


嘿,好奇你最终做了什么? - Azarro
我放弃了整个东西,并通过SSH在我的远程上拉取了repo,在那里我运行了docker-compose,因为我已经花了很多时间在github actions上。 - nixn
3
明白了。顺便说一句,我一直在按照你第二个选项大致描述的方式进行操作,使用Github Actions非常有效。我基本上使用docker compose build构建(在之前的步骤中创建任何可能需要的.env文件),将其推送到DigitalOcean的容器注册表,然后ssh进入一个目录,在那里运行我的生产compose文件(我在该节点上使用docker swarm / stack deploy,但docker compose也可以)。工作得相当不错! - Azarro
1
如果您能与我们分享一些最简代码,那将非常酷! - nixn
1
已将其添加为答案 - 希望有所帮助! - Azarro
显示剩余3条评论
1个回答

11

因为这样更简洁,所以我决定将此作为答案而非评论。

这是一个要点:https://gist.github.com/Aldo111/702f1146fb88f2c14f7b5955bec3d101

name: Server Build & Push

on:
  push:
    branches: [main]
    paths:
      - 'server/**'
      - 'shared/**'
      - docker-compose.prod.yml
      - Dockerfile

jobs:
  build_and_push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the repo
        uses: actions/checkout@v2
      - name: Create env file
        run: |
          touch .env
          echo "${{ secrets.SERVER_ENV_PROD }}" > .env
          cat .env
      - name: Build image
        run: docker compose -f docker-compose.prod.yml build

      - name: Install doctl
        uses: digitalocean/action-doctl@v2
        with:
          token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

      - name: Log in to DO Container Registry
        run: doctl registry login --expiry-seconds 600

      - name: Push image to DO Container Registry
        run: docker compose -f docker-compose.prod.yml push

      - name: Deploy Stack
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.GL_SSH_HOST }}
          username: ${{ secrets.GL_SSH_USERNAME }}
          key: ${{ secrets.GL_SSH_SECRET }}
          port: ${{ secrets.GL_SSH_PORT }}
          script: |
            cd /srv/www/game
            ./init.sh

在最后一步,我的目录中只包含一个.env文件和我的生产Compose文件,但在实际运行之前,这些东西也可以作为此工作流程的另一步进行rsync/copy/自动化处理。
我的init.sh文件只包含:
docker stack deploy -c <(docker-compose -f docker-compose.yml config) game --with-registry-auth
with-registry-auth部分很重要,因为我的docker-compose文件有使用DigitalOcean容器注册表中的容器的image字段。所以在服务器上,当我第一次设置目录时,我已经登录了一次。
有了这个命令,docker会根据需要拉取相关的镜像,并使用环境变量(即docker-compose -f docker-compose.yml config会预处理具有相同目录下.env文件的Compose文件,因为stack deploy不使用.env),并重新启动需要的服务!
这可以被进一步简化和优化,但在我的使用情况下,这种方式已经非常有效。

我使用了你的解决方案。不幸的是,工作流程中的构建/推送时间为0秒。它根本没有构建/拉取镜像。你有任何线索吗?为什么会这样? - Tivi
如果您能分享您的docker-compose文件,那将是非常有帮助的!谢谢! - Tivi
1
嘿!我的最佳猜测是 - 你的镜像/容器注册表设置好了吗?我使用DigitalOcean的容器注册表。如果注册表端一切正常,也许与注册表身份验证或环境变量有关。你能从构建日志中获取任何信息吗?这是我的生产组合 - https://gist.github.com/Aldo111/fd114fcef8626b9fc6e7b3948dc57e4b(在这种情况下,“server”容器是我关心拉取/推送的唯一一个镜像) - Azarro
非常感谢!你帮了我很多。我的docker-compose文件确实有问题。我忘记添加build,而且image没有像你一样指向我的registry.digitalocean.com/<my digitalocean registry>。现在它已经可以正常工作了,谢谢! - Tivi
1
很高兴听到这个好消息!希望项目顺利完成! - Azarro
大家好!我也在尝试同样的事情,对我来说,GitHub操作已经成功完成,但是Docker容器不可用。请问有人可以建议我缺少什么吗?这是我的操作 - https://dev59.com/Esj6oIgBc1ULPQZFU9fJ - Tarak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接