Инструменты пользователя

Инструменты сайта


develop:gh_actions

GitHub Actions

Введение

Сервис GitHub, который позволяет автоматизировать любой процесс связанный с деплоем кода на продакшн сервер. Код проекта выполняется на виртуальных серверах GH и далее доставляется куда нужно

:!: more

Имеет множество готовых решений, шаблонов и т.д.
Файлы располагаются во вложенной директории «./GitHub/workflows/.yml», файлы в формате yml
Можно работать в онлайн редакторе

Workflow

Поток выполнения действий
Задачи внутри - джобы (jobs), которые состоят из шагов (steps)

:!: more

Workflow обычно выполняет какую то большую задачу (очевидно правильно разбивать «одна задача - один воркфлоу»), их может быть множество, могут выполняться как последовательно так и параллельно, как и джобы

Может быть вызван автоматически, вручную либо выполняться по расписанию
Пример workflow:

name: Print workflow 
  # запуск вручную
on: workflow_dispatch

jobs: 
    # название джобы
  print_hello:
      # среда для запуска джобы
    runs-on: ubuntu-latest
    
    steps:
      - name: Print hello
          # команда которая будет выполнена в терминале
        run: echo "Hello world" 

В этом примере три логических блока:

  • параметры самого воркфлоу (name и on (пар-р запуска)),
  • настройка джоб (название и runs-on (инструкция для докера))
  • и шаги (так же название и run (команда для выполнения))

Jobs

«Джобы выполняются на разных VM», для выполнения в рамках одной VM есть steps

:!: Порядок выполнения jobs

Параллельное выполнение

jobs:
  print_hello:
    runs-on: ubuntu-latest
    steps:
      - name: Print hello
        run: echo "Hello world!"
  
  print_full_tech_info:
    runs-on: ubuntu-latest
    steps:
      - name: print full_tech_info
        run: sudo lshw
  
  print_short_tech_info:
    runs-on: ubuntu-latest
    steps:
      - name:
        run: sudo lshw -short

В интерфейсе GH, данные джобы будут в одном блоке, вместе, выполнялись параллельно

Для последовательного выполнения используется параметр «needs»

jobs:
  print_hello:
    runs-on: ubuntu-latest
    steps:
      - name: print hello
        run: echo "hello world" 

  print_full_tech_info:
    needs: print_hello
    runs-on: ubuntu-latest
    steps:
      - name: print_full_tech_info
        run: sudo lshw

  print_short_tech_info:
    needs: print_full_tech_info
    runs-on: ubuntu-latest
    steps:
      - name: print_short_tech_info
        run: sudo lswh -short

В интерфейсе GH джобы будут размещены в разных блоках, друг за другом
Если одна из них завершится с ошибкой, то остальные выполняться не будут

Такие цепочки зависимостей можно строить и целыми workflow

name: my_Workflow
  # секция условий выполнения текущего флоу
on:
  workflow_run:
    workflows: ["Run tests"]
    branches: [main]
    types:
        # статус выполнения первого флоу
      - completed

Actions

Вместо инструкции «run», для вызова команд, можно использовать готовые модули или решения, написанные другими разработчиками, они распространяются бесплатно на маркетплейсе GH

:!: пример

Например популярный экшен для загрузки кода из репозитория, «checkout@v3»

name: print workflow
on: workflow_dispatch

jobs:
  checkout:
    runs-on: ubuntu-latest
    steps:
      - name: checkout_repo
        uses: actions/checkout@v3

Примеры

:!: Большой пример

Главный экшен «ci-production» является точкой входа, внутри запускает доп экшены
Выполняются на self-hosted раннерах
Настроено несколько окружений, содержащих свой набор переменных, задаются в настройках репозитория

«ci-production.yml»
Триггеримся на пуш тега с формате «release-«
Нюанс в том что сработает пуш этого тега в любую ветку а выпуск релиза предполагается наверно из мастера

name: ci-production
on:
  push:
    tags:
      - 'release-*'
 
jobs:
  build:
    uses: ./.github/workflows/build.yml
    secrets: inherit
 
  deploy-stage:
    needs: build
    uses: ./.github/workflows/deploy.yml
    with:
      environment: stage
    secrets: inherit
 
  deploy-prod:
    needs: deploy-stage
    uses: ./.github/workflows/deploy.yml
    with:
      environment: prod
    secrets: inherit

Для запуска тестов делаем flow с триггером на пуш в любую ветку кроме «master», в него как раз предполагается пуш релизного тега, иначе запускаются оба флоу

name: ci-test
on:
  push:
    branches:
      - '**'
      - '!master'
 
jobs:
  build:
    uses: ./.github/workflows/build.yml
    secrets: inherit
 
  deploy-stage:
    needs: build
    uses: ./.github/workflows/deploy.yml
    with:
      environment: stage
    secrets: inherit

«build.yml»

name: build
on:
  workflow_call:
 
jobs:
  build:
    runs-on:
      - self-hosted
      - Linux
      - kube-common
 
    steps:
      - uses: actions/checkout@v4
 
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: 17
          distribution: 'adopt'
 
      - name: Validate Gradle Wrapper
        uses: gradle/wrapper-validation-action@v2.1.1
 
      - name: Compile
        run: sudo bash ./gradlew :compileJava
 
      - name: Test
        run: sudo bash ./gradlew :test
 
      - name: Build
        run: sudo bash ./gradlew :bootJar
 
      - name: Inject GitHub variables
        uses: rlespinasse/github-slug-action@v4
 
      - name: Set docker tags
        run: |
          echo 'DOCKER_TAGS<<EOF' >> $GITHUB_ENV
          # В этой переменной последний тег, если нет собственного то в нем будет название ветки
          if [[ "$GITHUB_REF_SLUG" =~ "release-".* ]]; then
            echo "registry.myapp.ru/myapp:$GITHUB_REF_SLUG-$GITHUB_SHA_SHORT"
            echo "registry.myapp.ru/myapp:latest"
          else
            echo "registry.myapp.ru/myapp:branch-$GITHUB_REF_SLUG-$GITHUB_SHA_SHORT"
          fi >> $GITHUB_ENV
          echo 'EOF' >> $GITHUB_ENV
          cat $GITHUB_ENV
 
      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: registry.myapp.ru
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
 
      - name: Setup Docker Buildx
        uses: docker/setup-buildx-action@v3
 
      - name: Build and push image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./docker/Dockerfile
          push: true
          tags: ${{ env.DOCKER_TAGS }}

«deploy.yml»
Деплоится на удаленный сервер, кредлы ssh сохранены в секретах репы
Для применения окружения переменных «stage», нужен блок «environment»

name: deploy
on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
 
jobs:
  deploy:
    runs-on:
      - self-hosted
      - Linux
      - kube-common
 
    environment:
      name: ${{ inputs.environment }}
 
    steps:
      - uses: actions/checkout@v4
 
      # Для того чтобы задеплоить именно эту версию образа, чтобы и для тестов тоже работало
      # Указываем в докер-компоуз тег образа который мы добавляли на прошлом шаге 
      - name: Inject GitHub variables
        uses: rlespinasse/github-slug-action@v4
 
      - name: Get docker-image tags
        run: |
          echo 'DOCKER_TAGS<<EOF' >> $GITHUB_ENV
          if [[ "$GITHUB_REF_SLUG" =~ "release-".* ]]; then
            echo "$GITHUB_REF_SLUG-$GITHUB_SHA_SHORT"
          else
            echo "branch-$GITHUB_REF_SLUG-$GITHUB_SHA_SHORT"
          fi >> $GITHUB_ENV
          echo 'EOF' >> $GITHUB_ENV
          cat $GITHUB_ENV
 
      # Далее добавить еще один replace в компоуз
      - name: Set secrets & environment
        run: |
          cd ./docker/
          sed -i 's/<DATABASE_NAME>/${{ vars.DATABASE_NAME }}/g' ./docker_compose_myapp.yml
          sed -i 's/<DATABASE_USER_NAME>/${{ vars.DATABASE_USER_NAME }}/g' ./docker_compose_myapp.yml
 
      - name: Deploy on remote host
        uses: cross-the-world/ssh-scp-ssh-pipelines@latest
        with:
          host: ${{ secrets.SSH_HOST }}
          user: ${{ secrets.SSH_USER }}
          pass: ${{ secrets.SSH_PASS }}
          first_ssh: |
            echo '===== PREPARE HOST ====='
            sudo mkdir -p /opt/${{ vars.APP_DIRECTORY }}/
            sudo mkdir -p /opt/pgdata/
            sudo chown -R ${{ secrets.SSH_USER }}. /opt/
 
          scp: |
            echo '===== SENDING FILES ====='
            './docker/postgres' => /opt/${{ vars.APP_DIRECTORY }}/
            './docker/docker_compose_myapp.yml' => /opt/${{ vars.APP_DIRECTORY }}/
 
          last_ssh: |
            echo '===== LOGIN TO REGISTRY ====='
            sudo docker login registry.myapp.io -u '${{ secrets.DOCKER_USERNAME }}' -p '${{ secrets.DOCKER_PASSWORD }}'
 
            echo '===== RESTART DOCKER-COMPOSE ====='
            cd /opt/${{ vars.APP_DIRECTORY }}/
            sudo docker-compose -f docker_compose_myapp.yml down
            sudo docker-compose -f docker_compose_myapp.yml up -d
 
 
develop/gh_actions.txt · Последнее изменение: 2024/02/19 03:46 — admin