В прошлой заметке был сделан процесс сборки приложения написанного на 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"]