Показаны различия между двумя версиями страницы.
Следующая версия | Предыдущая версия | ||
develop:gh_actions [2024/01/26 05:25] admin создано |
develop:gh_actions [2024/02/19 03:46] (текущий) admin |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
====== GitHub Actions ====== | ====== GitHub Actions ====== | ||
+ | ===== Введение ===== | ||
+ | Сервис GitHub, который позволяет автоматизировать любой процесс связанный с деплоем кода на продакшн сервер. Код проекта выполняется на виртуальных серверах GH и далее доставляется куда нужно\\ | ||
+ | < | ||
+ | < | ||
+ | Имеет множество готовых решений, | ||
+ | Файлы располагаются во вложенной директории " | ||
+ | Можно работать в онлайн редакторе\\ | ||
+ | </ | ||
- | ===== ===== | ||
- | ===== ===== | ||
- | ===== ===== | ||
+ | ==== Workflow ==== | ||
+ | Поток выполнения действий\\ | ||
+ | Задачи внутри - джобы (**jobs**), которые состоят из шагов (**steps**)\\ | ||
+ | < | ||
+ | < | ||
+ | Workflow обычно выполняет какую то большую задачу (очевидно правильно разбивать " | ||
- | ==== ==== | + | Может быть вызван автоматически, |
- | ==== ==== | + | Пример workflow: |
- | ==== ==== | + | <code yaml> |
+ | name: Print workflow | ||
+ | # запуск вручную | ||
+ | on: workflow_dispatch | ||
+ | |||
+ | jobs: | ||
+ | # название джобы | ||
+ | | ||
+ | # среда для запуска джобы | ||
+ | runs-on: ubuntu-latest | ||
+ | |||
+ | steps: | ||
+ | - name: Print hello | ||
+ | # команда которая будет выполнена в терминале | ||
+ | run: echo "Hello world" | ||
+ | </ | ||
+ | В этом примере три логических блока: | ||
+ | * параметры самого воркфлоу (name и on (пар-р запуска)), | ||
+ | * настройка джоб (название и runs-on (инструкция для докера)) | ||
+ | * и шаги (так же название и run (команда для выполнения)) | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ==== Jobs ==== | ||
+ | " | ||
< | < | ||
- | < | + | < |
+ | |||
+ | Параллельное выполнение | ||
+ | <code yaml> | ||
+ | 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, данные джобы будут в одном блоке, вместе, | ||
+ | |||
+ | Для последовательного выполнения используется параметр " | ||
+ | <code yaml> | ||
+ | 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\\ | ||
+ | <code yaml> | ||
+ | name: my_Workflow | ||
+ | # секция условий выполнения текущего флоу | ||
+ | on: | ||
+ | workflow_run: | ||
+ | workflows: ["Run tests" | ||
+ | branches: [main] | ||
+ | types: | ||
+ | # статус выполнения первого флоу | ||
+ | - completed | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ==== Actions ==== | ||
+ | Вместо инструкции " | ||
+ | |||
+ | < | ||
+ | < | ||
+ | Например популярный экшен для загрузки кода из репозитория, | ||
+ | |||
+ | <code yaml> | ||
+ | name: print workflow | ||
+ | on: workflow_dispatch | ||
+ | |||
+ | jobs: | ||
+ | checkout: | ||
+ | runs-on: ubuntu-latest | ||
+ | steps: | ||
+ | - name: checkout_repo | ||
+ | uses: actions/ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ==== Примеры ==== | ||
+ | |||
+ | < | ||
+ | < | ||
+ | Главный экшен " | ||
+ | Выполняются на self-hosted раннерах\\ | ||
+ | Настроено несколько окружений, | ||
+ | |||
+ | |||
+ | |||
+ | " | ||
+ | Триггеримся на пуш тега с формате " | ||
+ | Нюанс в том что сработает пуш этого тега в любую ветку а выпуск релиза предполагается наверно из мастера\\ | ||
<code bash> | <code bash> | ||
+ | name: ci-production | ||
+ | on: | ||
+ | push: | ||
+ | tags: | ||
+ | - ' | ||
+ | |||
+ | jobs: | ||
+ | build: | ||
+ | uses: ./ | ||
+ | secrets: inherit | ||
+ | |||
+ | deploy-stage: | ||
+ | needs: build | ||
+ | uses: ./ | ||
+ | with: | ||
+ | environment: | ||
+ | secrets: inherit | ||
+ | |||
+ | deploy-prod: | ||
+ | needs: deploy-stage | ||
+ | uses: ./ | ||
+ | with: | ||
+ | environment: | ||
+ | secrets: inherit | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | Для запуска тестов делаем flow с триггером на пуш в любую ветку кроме " | ||
+ | |||
+ | <code bash> | ||
+ | name: ci-test | ||
+ | on: | ||
+ | push: | ||
+ | branches: | ||
+ | - ' | ||
+ | - ' | ||
+ | |||
+ | jobs: | ||
+ | build: | ||
+ | uses: ./ | ||
+ | secrets: inherit | ||
+ | |||
+ | deploy-stage: | ||
+ | needs: build | ||
+ | uses: ./ | ||
+ | with: | ||
+ | environment: | ||
+ | secrets: inherit | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | " | ||
+ | <code bash> | ||
+ | name: build | ||
+ | on: | ||
+ | workflow_call: | ||
+ | |||
+ | jobs: | ||
+ | build: | ||
+ | runs-on: | ||
+ | - self-hosted | ||
+ | - Linux | ||
+ | - kube-common | ||
+ | |||
+ | steps: | ||
+ | - uses: actions/ | ||
+ | |||
+ | - name: Set up JDK 17 | ||
+ | uses: actions/ | ||
+ | with: | ||
+ | java-version: | ||
+ | distribution: | ||
+ | |||
+ | - name: Validate Gradle Wrapper | ||
+ | uses: gradle/ | ||
+ | |||
+ | - name: Compile | ||
+ | run: sudo bash ./gradlew : | ||
+ | |||
+ | - name: Test | ||
+ | run: sudo bash ./gradlew :test | ||
+ | |||
+ | - name: Build | ||
+ | run: sudo bash ./gradlew :bootJar | ||
+ | |||
+ | - name: Inject GitHub variables | ||
+ | uses: rlespinasse/ | ||
+ | |||
+ | - name: Set docker tags | ||
+ | run: | | ||
+ | echo ' | ||
+ | # В этой переменной последний тег, если нет собственного то в нем будет название ветки | ||
+ | if [[ " | ||
+ | echo " | ||
+ | echo " | ||
+ | else | ||
+ | echo " | ||
+ | fi >> $GITHUB_ENV | ||
+ | echo ' | ||
+ | cat $GITHUB_ENV | ||
+ | |||
+ | - name: Login to Registry | ||
+ | uses: docker/ | ||
+ | with: | ||
+ | registry: registry.myapp.ru | ||
+ | username: ${{ secrets.DOCKER_USERNAME }} | ||
+ | password: ${{ secrets.DOCKER_PASSWORD }} | ||
+ | |||
+ | - name: Setup Docker Buildx | ||
+ | uses: docker/ | ||
+ | |||
+ | - name: Build and push image | ||
+ | uses: docker/ | ||
+ | with: | ||
+ | context: . | ||
+ | file: ./ | ||
+ | push: true | ||
+ | tags: ${{ env.DOCKER_TAGS }} | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | " | ||
+ | Деплоится на удаленный сервер, | ||
+ | Для применения окружения переменных " | ||
+ | <code bash> | ||
+ | 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/ | ||
+ | |||
+ | # Для того чтобы задеплоить именно эту версию образа, | ||
+ | # Указываем в докер-компоуз тег образа который мы добавляли на прошлом шаге | ||
+ | - name: Inject GitHub variables | ||
+ | uses: rlespinasse/ | ||
+ | |||
+ | - name: Get docker-image tags | ||
+ | run: | | ||
+ | echo ' | ||
+ | if [[ " | ||
+ | echo " | ||
+ | else | ||
+ | echo " | ||
+ | fi >> $GITHUB_ENV | ||
+ | echo ' | ||
+ | cat $GITHUB_ENV | ||
+ | |||
+ | # Далее добавить еще один replace в компоуз | ||
+ | - name: Set secrets & environment | ||
+ | run: | | ||
+ | cd ./docker/ | ||
+ | sed -i ' | ||
+ | sed -i ' | ||
+ | |||
+ | - name: Deploy on remote host | ||
+ | uses: cross-the-world/ | ||
+ | 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 / | ||
+ | sudo chown -R ${{ secrets.SSH_USER }}. /opt/ | ||
+ | |||
+ | scp: | | ||
+ | echo '===== SENDING FILES =====' | ||
+ | ' | ||
+ | ' | ||
+ | |||
+ | 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 | ||
</ | </ | ||
</ | </ | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ==== ==== | ||
+ | |||
+ | |||
+ | |||