Введение
Автоматизируя процесс развертывания изменений кода в экземпляре Amazon Web Services (AWS) Elastic Compute Cloud (EC2) с помощью Github Actions и Docker Hub, разработчик в итоге экономит время и силы.
В этом руководстве мы пошагово настроим экземпляр AWS EC2, создадим и добавим в DockerHub образ Docker и настроим рабочий поток Github Actions для автоматизации процесса развертывания. В итоге научимся оптимизировать рабочий процесс развертывания, уменьшая риск человеческой ошибки.
Необходимые условия
1. Код для сборки
Он нужен для создания образа Docker — легковесного, автономного, исполняемого пакета, в котором содержится все необходимое для запуска приложения, в том числе код, библиотеки и зависимости.
2. Экземпляр AWS EC2 с файлом .pem и установленным Docker
В AWS EC2 развертывается приложение. Используем экземпляр Ubuntu AWS EC2, хотя это не обязательно должен быть Ubuntu. Настраивается AWS EC2 согласно официальной документации AWS. Файл .pem связан с экземпляром для SSH-доступа. Docker устанавливается в экземпляре AWS EC2 согласно официальной документации Docker.
3. Учетная запись Docker Hub с токеном доступа
Docker Hub — это облачная служба реестра для хранения и обмена образами Docker. Учетную запись для их размещения в ней создаем здесь. Затем, следуя инструкциям официальной документации Docker, генерируем токен доступа для аутентификации в рабочем потоке Github Actions через Docker Hub.
Приступим к автоматизации развертывания AWS EC2.
Создание Dockerfile
Чтобы сделать Docker-образ приложения, создадим dockerfile
, в котором описывается сборка образа.
- В корневом каталоге проекта с помощью текстового редактора создаем файл
dockerfile
. - В
dockerfile
начинаем с указания базового образа, например для приложения на Go это официальный Docker-образ Golang:
##указываем базовый образ
FROM golang:1.19-alpine
Этой строкой за основу Docker-образа берем образ golang:1.19-alpine
.
3. Затем в Docker-образе указываем рабочий каталог для приложения:
##создаем папку APP
RUN mkdir /app
##задаем главный каталог
WORKDIR /app
Этими строками создаем в Docker-образе каталог app
и делаем его рабочим.
4. Копируем остальную часть кода приложения в Docker-образ:
##копируем весь файл в приложение
ADD . /app
Этой строкой в каталог /app
Docker-образа копируется остальная часть кода приложения.
5. Создаем исполняемый файл для приложения:
##создаем исполняемый файл
RUN go build -o main .
Чтобы создать для приложения исполняемый файл main
, этой строкой в Docker-образе запускается команда go build
.
6. Указываем команду, выполняемую при запуске контейнера Docker:
##запускаем исполняемый файл
CMD ["/app/main"]
Этой строкой при запуске контейнера Docker запускается исполняемый файл /app/main
.
Вот готовый Dockerfile:
##в качестве базового используем официальный Docker-образ Golang FROM golang:1.19-alpine ##создаем папку APP RUN mkdir /app ##задаем главный каталог WORKDIR /app ##копируем весь файл в приложение ADD . /app ##создаем исполняемый файл RUN go build -o main . ##запускаем исполняемый файл CMD ["/app/main"]
Создадим Docker-образ и отправим его в Docker Hub.
Настройка рабочего процесса GitHub
Настраивая рабочий процесс GitHub, мы автоматизируем тестирование, сборку и развертывание кода и обеспечиваем последовательное и надежное выполнение этих задач.
Чтобы настроить рабочий процесс GitHub, создадим в каталоге репозитория .github/workflows
файл YAML, например main.yml
. В этом файле определяются запускаемые задания и выполняемые экшены.
Каждое задание состоит из шагов, на каждом шаге выполняется конкретный экшен. Экшены — это многократно используемые блоки кода для выполнения конкретных задач, например проверки кода, создания Docker-образа или развертывания кода у облачного провайдера.
Вот пример простого YAML-файла для сборки и отправки Docker-образа в Docker Hub, когда в ветке main
появляется новый push
:
# Запускается рабочий процесс, когда в ветке main появляется push on: push: branches: - main jobs: build: # На компьютере с Ubuntu запускается задание name: Build runs-on: ubuntu-latest steps: # Извлекаем код из репозитория - name: Checkout uses: actions/checkout@v3 # Входим в Docker Hub, используя secrets - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_TOKEN }} # Настраиваем Docker Buildx - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 # Создаем Docker-образ и отправляем его в Docker Hub - name: Build and push uses: docker/build-push-action@v3 with: context: . file: ./Dockerfile push: true tags: ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }}:latest # Запускаем удаленные команды в экземпляре EC2 через SSH - name: executing remote ssh commands using password uses: appleboy/[email protected] with: host: ${{ secrets.EC2_HOST }} username: ${{ secrets.EC2_USERNAME }} key: ${{ secrets.EC2_KEY }} port: ${{ secrets.EC2_PORT }} # Удаленные команды, выполняемые в экземпляре EC2 script: | touch deploy.txt echo "Great, it works! at $(TZ='Asia/Jakarta' date "+%A %d-%b-%Y %H:%M:%S %Z")" >> deploy.txt sudo chmod 777 /var/run/docker.sock docker pull ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }}:latest docker stop ${{ secrets.CONTAINER }} docker rm ${{ secrets.CONTAINER }} docker rmi ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }} docker run --name ${{ secrets.CONTAINER }} -d -p 80:8000 ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }}
Разбор рабочего процесса GitHub
on:
push:
branches:
- main
Здесь определяется событие, которым запускается рабочий процесс. В данном случае это появление нового push
в ветке main
.
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
Здесь определяется задание build
, запускаемое в рабочем процессе на последней версии Ubuntu.
- name: Checkout
uses: actions/checkout@v3
На этом шаге код извлекается из репозитория в runner
.
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_TOKEN }}
На этом шаге входим в Docker Hub, вводя имя пользователя и токен, сохраненный в настройках репозитория как secrets
.
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
На этом шаге настраивается CLI-плагин Docker Buildx
, которым расширяются возможности интерфейса командной строки Docker.
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }}:latest
На этом шаге с помощью Dockerfile в текущем каталоге создается Docker-образ и по указанным тегам отправляется в Docker Hub.
# Запускаем удаленные команды в экземпляре EC2 через SSH - name: executing remote ssh commands using password uses: appleboy/[email protected] with: host: ${{ secrets.EC2_HOST }} username: ${{ secrets.EC2_USERNAME }} key: ${{ secrets.EC2_KEY }} port: ${{ secrets.EC2_PORT }} # Удаленные команды, выполняемые в экземпляре EC2 script: | touch deploy.txt echo "Great, it works! at $(TZ='Asia/Jakarta' date "+%A %d-%b-%Y %H:%M:%S %Z")" >> deploy.txt sudo chmod 777 /var/run/docker.sock docker pull ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }}:latest docker stop ${{ secrets.CONTAINER }} docker rm ${{ secrets.CONTAINER }} docker rmi ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }} docker run --name ${{ secrets.CONTAINER }} -d -p 80:8000 ${{ secrets.DOCKER_USER }}/${{ secrets.IMAGE }}
- В этом блоке кода используется экшен
appleboy/ssh-action
для выполнения удаленной команды SSH на сервере, указанном в файлеsecrets
. Выполняемый сценарий определяется параметромscript
. - Сценарий начинается с создания нового файла
deploy.txt
и добавления к нему строкиGreat, it works!
вместе с текущей датой и временем в часовом поясе Азии/Джакарты или вашем. - Затем, чтобы изменить разрешения сокет-файла Docker для доступа к нему текущего пользователя, выполняется команда
sudo chmod 777 /var/run/docker.sock
. - Для получения последней версии Docker-образа, указанной в файле
secrets
, применяется командаdocker pull
. - Команды
docker stop
,docker rm
иdocker rmi
используются для остановки и удаления любого имеющегося контейнера и образа Docker с тем же именем, что указан в файлеsecrets
. - Команда
docker run
используется для запуска нового контейнера Docker с именем, указанным в файлеsecrets
, и с помощью образа изsecrets
. - Флагом
-d
в фоновом режиме запускается контейнер как процесс демона. - Флагом
-p 80:8000
порт 80 хоста сопоставляется с портом 8000 контейнера: получаем доступ к контейнеру по HTTP через порт 80. - Через флаг
-e
задаются переменные окружения для контейнера, например DB Host, DB Password, JWT Key и т. д.
В итоге в этом блоке кода получается последняя версия Docker-образа, останавливаются и удаляются любые имеющиеся контейнеры с одинаковым именем, запускается новый контейнер, а порт контейнера 8000 сопоставляется с портом хоста 80.
Настройка секретных переменных
Чтобы развернуть приложение в AWS EC2, настроим несколько секретных переменных в репозитории GitHub. Эти secrets надежно зашифрованы и хранятся в GitHub, доступ к ним имеют только авторизованные пользователи.
- Переходим в репозиторий GitHub.
- Нажимаем на вкладку Settings («Настройки»).
- Выбираем слева Secrets.
- Попадаем на страницу Actions secrets and variables («Секреты и переменные экшенов») репозитория. Здесь создаются, редактируются и удаляются секреты для рабочих процессов GitHub Actions.
Вот список необходимых секретных переменных с кратким описанием.
DOCKER_USER
: имя пользователя Docker Hub.DOCKER_TOKEN
: токен доступа с разрешением отправлять образы в репозиторий Docker Hub.IMAGE
: имя Docker-образа.CONTAINER
: имя контейнера Docker для запуска приложения.EC2_HOST
: IP-адрес или доменное имя экземпляра EC2, напримерec2–xx–xxx–xxx–xx.ap-southeast-1.compute.amazonaws.com
.EC2_USERNAME
: имя пользователя для входа в экземпляр EC2, обычно этоubuntu
.EC2_KEY
: закрытый ключ для входа в экземпляр EC2.EC2_PORT
: SSH-порт для подключения к экземпляру EC2, по умолчанию22
.
Обязательно настройте эти секретные переменные в репозитории GitHub перед запуском рабочего процесса.
Выполнение рабочего процесса
После настройки фиксируем изменения кода в ветке main
репозитория: рабочий процесс запустится автоматически.
Чтобы проверить его статус, переходим на вкладку Actions репозитория GitHub. Здесь имеется список всех выполненных рабочих процессов и их статус. Выбрав рабочий процесс, просматриваем информацию о нем, включая любые ошибки и предупреждения:
Если рабочий процесс выполнится, появится сообщение о том, что развертывание завершено. Можно также проверить работоспособность сайта.
Если рабочий процесс не запускается, возможна проблема с конфигурацией или кодом. Чтобы выявить проблему, просмотрите сообщения об ошибках в логах рабочего процесса и внесите в него или код любые необходимые изменения. Проверьте также, не совпадают ли секретные переменные.
В целом, в выполнении рабочего процесса GitHub нет ничего сложного: с ним разработка и развертывание значительно оптимизируются. При правильной настройке и конфигурации автоматизируются многие времязатратные задачи, связанные с разработкой ПО, и вы можете сосредоточиться на создании отличных продуктов и сервисов.
Заключение
В этом руководстве мы пошагово настроили базовый рабочий процесс GitHub для развертывания контейнеризированного веб-приложения. С мощью GitHub Actions процесс развертывания приложения автоматизируется, а время высвобождается на другие важные задачи. Надеемся, статья была полезной для понимания основ GitHub Actions, Docker, Docker Hub и того, как применять их вместе для упрощения рабочего процесса.
Продолжая работать над проектами, вы сможете использовать освоенные концепции для создания более сложных и специализированных рабочих процессов, настроить их под себя. Возможности безграничны — проявите творческий подход, и вы сможете создать мощные рабочие процессы для достижения ваших целей быстрее и меньшими усилиями.
Читайте также:
- Запускаем Rocket REST API на AWS
- Автоматическое масштабирование CI с помощью Kraken CI
- Как протестировать код на Go с Github Actions
Читайте нас в Telegram, VK и Дзен
Перевод статьи Muhammad Habibullah: Easy and Fast : Automating AWS EC2 Deployment with GitHub Actions and Docker Hub