В прошлой заметке был сделан процесс сборки приложения написанного на Go и деплой его на собственный VPS. Но хотя там и используется кэширование в каждой задаче, в процессе есть дублирующиеся действия. В этой заметке доработаем процесс.

Нам нужно избавится от двойной сборки приложения. Первый раз оно собирается для тестов, второй внутри образа Docker. Для оптимизации процесса будем использовать передачу артефактов между задачами с помощью actions/upload-artifact и actions/download-artifact. Идея в том, что бы собрать приложение в первой задаче, а во вторую задачу передать уже собранное приложение. Это похоже на multistage сборку из docker.

name: Go

on:
  push:
    branches: [ "main" ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:

  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: 'stable'

      - name: Build
        run: CGO_ENABLED=1 go build -v -ldflags "-s -w -extldflags '-static'" -o app

      - name: Test
        run: go test -v ./...

      - name: Pack executable
        run: |
          sudo apt install upx
          upx ./app

      - name: upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: my-artifact
          path: |
            Dockerfile.action
            app

  build-and-push-image:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:

      - name: Update cert
        run: |
          sudo update-ca-certificates
          sudo cp /etc/ssl/certs/ca-certificates.crt ca-certificates.crt
          mkdir zoneinfo
          sudo cp -r /usr/share/zoneinfo/* ./zoneinfo

      - name: Log in to the Container registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - uses: actions/download-artifact@v3
        with:
          name: my-artifact

      - name: set permissions
        run: chmod a+x app

      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        with:
          context: .
          file: Dockerfile.action
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    runs-on: self-hosted
    needs: build-and-push-image

    steps:
      - name: Log in to the Container registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Run container
        run: |
          cd ~
          docker-compose up --build --pull=always &

Заметьте, что во второй задаче репозиторий не скачивается, следовательно никаких файлов из него нет и если они требуются, то их нужно передать через артефакты (как Dockerfile.action)

Обратите внимание на шаг “Update cert”. В нем я копирую корневые сертификаты и таймзоны в домашнюю папку, иначе при сборе образа Docker эти файлы не доступны. Дальше не стал разбираться в этом вопросе.

Добавим в папку проекта новый файл Dockerfile.action. Через него будем собирать образ. Старый Dockerfile тоже оставим на случай, если потребуется собрать образ локально (не через workflow) для каких либо целей.

FROM scratch
COPY /ca-certificates.crt /etc/ssl/certs/
COPY /zoneinfo/ /usr/share/zoneinfo/
COPY /app /app
CMD ["/app"]

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *