이 포스팅은 GitHub Actions를 사용하여 이미지를 생성하고, Amazon Elastic Container Registry (ECR)에 업로드한 후, EC2 인스턴스에 배포하는 단계를 설명합니다.
이 과정은 크게 아래와 같이 이루어집니다.
- 개발자가 trigger: 개발자가 github에 코드를 commit / push 등 엑션을 하하고, 리포지토리에서 action trigger가 실행
- Action에서 이미지 빌딩 및 푸시: github action에서 이미지 빌드: Dockerfile을 이용하여 이미지를 만들고, 만든 이미지를 ECR에 PUSH
- Actiond에서 SSH 접속 후 Pull 및 Run: Action에서 EC2인스턴스에 SSH로 접속하여, ECR에 올려져있는 이미지를 PULL 및 RUN
이 과정을 위해, 사전 요구사항 및 단계는 다음과 같이 나뉩니다:
사전 요구사항(Preliquesite)
- Dockerfile 만들기
- IAM 생성 및 권한 설정
- Github secrets 설정하기
Github Action 설정
- Action yaml파일 설정하기
- AWS 자격증명: AWS 액세스 키와 시크릿 키, 그리고 지정한 AWS 리전을 사용하여 AWS 자격증명을 설정합니다.
- ECR에 로그인: Docker를 ECR에 푸시하기 전에 ECR에 로그인을 수행
- Docker 이미지 빌드: Docker 이미지를 빌드
- Docker 이미지 ECR로 푸시: 이미지를 ECR로 푸시하기 위해 해당 이미지를 태깅하고, ECR에 로그인한 뒤 이미지를 푸시합니다.
- EC2 인스턴스로 SSH 접속:
5.1암호화된 PEM 파일을 사용하여 EC2 인스턴스로 SSH 접속합니다.
SSH로 EC2 인스턴스에 접속한 후, ECR에서 이미지를 풀고 해당 이미지를 실행합니다.
사전 요구사항
1. Dockerifle 생성: ECR에 올려서 PUSH/PULL할 것이기 때문에, 간단한 Dockerfile을 하나 생성합니다.
//Dockerfile
# 베이스 이미지로 Python 3.8을 사용합니다.
FROM python:3.8
# 작업 디렉토리를 /app으로 설정합니다.
WORKDIR app
# 현재 디렉토리의 모든 파일을 /app 디렉토리로 복사합니다.
COPY . .
# Python 종속성을 설치합니다.b
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install uvicorn
# 앱을 실행합니다.
CMD ["uvicorn", "app:app", "--reload"]
아래와 같이 app.py (FastAPI의 앱)을 간단히 생성합니다.
//app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
requirements.txt도 하나 생성합니다.
//requirement.txt
fastapi
2. IAM 생성, 키 생성 및 권한 부여: IAM 생성및 EC2, ECR 관련 권한부여
AWS Identity and Access Management (IAM)은 Amazon Web Services (AWS)에서 제공하는 서비스로, AWS 리소스에 대한 액세스를 관리하고 보안을 강화하는 데 사용됩니다. IAM을 사용하여 AWS 계정에 사용자, 그룹 및 역할을 생성하고, 이러한 엔터티에 대한 권한을 정의하여 AWS 리소스에 대한 액세스를 제어할 수 있습니다. 본 과정에서는 github action으로 AWS 리소스(ECR, EC2)을 제어 하기 위함입니다.
권한은 아래와 같이, "AdministratorAccess" 와 "AmazonEC2ContainerRegistryFullAccess"을 할당했습니다.
3. Github secrets 설정: 리포지토리 내, Settings-Security 내 Secrets and variable - Actions 등록
Action secrets는 GitHub Actions 워크플로우에서 사용되는 민감한 정보를 안전하게 저장하고 관리하기 위한 기능입니다. Secrets는 암호화되어 안전한 저장소에 저장되며, 워크플로우 실행 시에만 필요한 환경 변수로 사용할 수 있습니다. Action에서 사용하게되는 변수들을 repository에서 안전하게 저장하고, action에서 사용하는 yaml파일에서 접근이 가능합니다.
다음과 같이 등록이 필요합니다.
- AWS_ACCESS_KEY_ID: AWS(Amazon Web Services) 계정에 액세스하는 데 사용되는 액세스 키의 ID 부분입니다. AWS API에 액세스할 때 사용
- AWS_SECRET_ACCESS_KEY: AWS(Amazon Web Services) 계정에 액세스하는 데 사용되는 액세스 키의 시크릿 키 부분입니다. AWS API에 액세스할 때 사용
- AWS_REGION: AWS 리소스가 위치한 지역(region)을 지정하는 변수. 참고로 ap-northeast-2=아시아 태평양(서울)입니다.
- REPO_NAME: ECR 리포지토리에 접근하는 데 사용되는 계정 ID 또는 별칭입니다. ECR에 도커 이미지를 푸시하거나 불러올 때 사용
- EC2_PRIVATE_KEY: AWS EC2 인스턴스에 SSH로 접속할 때 사용되는 개인 키(private key). EC2의 pem키의 내용을 그대로 copy & paste하시면 됩니다. "--benign", "--end"을 포함하여 plain text로 복붙하시면됩니다!
4. ECR 생성하기: dockerhub을 이용하셨다면, 같은 기능을 하는 AWS의 dockerhub라고 보셔도 무관합니다.
AWS 검색화면에서 ECR을 검색하여 다음과 같이, 리포지토리(repository)을 생성합니다. 아래와 같이 private으로 설정할 수 있습니다. 그리고, Repository name에보면, "숫자".dkr.ecr.ap-northeast-2.amazonaws.com 으로 나열되는데 "숫자"에 해당하는 부분이 aws_account_id이고, ap-northeast-2가 region입니다[1]. aws_account_id도 secret_key로 본 포스팅에서는 등록하였습니다.
[1] https://docs.aws.amazon.com/AmazonECR/latest/userguide/Registries.html#registry_auth
Action 설정하기
1. Action yaml파일 생성: github/workflows 디렉토리에 새 워크플로우 파일을 생성합니다. 예를 들어, deploy.yml 파일을 만들 수 있습니다. 아래와 같이 "set up a workflow yourself"을 눌러 workflow(yaml파일)을 처음부터 작성할 수 있습니다.
그리고, 아래와 같이 yaml파일의 초반부를 작성합니다.
name: Deploy to EC2 with ECR
on:
push:
branches:
- main # 배포할 브랜치를 선택합니다. 원하는 브랜치로 변경 가능
env:
EC2_USER: ubuntu
EC2_HOST: <EC2의 IPv4 공개IP>
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
AWS 자격증명: AWS 액세스 키와 시크릿 키, 그리고 지정한 AWS 리전을 사용하여 AWS 자격증명을 설정합니다.
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
ECR에 로그인: Docker를 ECR에 푸시하기 전에 ECR에 로그인을 수행
- name: Login to ECR
id: ecr
uses: jwalton/gh-ecr-login@v1
with:
access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
region: ${{ secrets.AWS_REGION }}
Docker 이미지 빌드: Docker 이미지를 빌드
- name: Build image
run: |
docker build --tag my-image:latest .
Docker 이미지 ECR로 푸시: 이미지를 ECR로 푸시하기 위해 해당 이미지를 태깅하고, ECR에 로그인한 뒤 이미지를 푸시합니다. 위의 단계에서 만든 "my-image:latest"의 이미지를 ECR로 푸시하기위해서, ECR에 로그인하고, ECR리포지토리에 맞게 테그명을 변경합니다. 만일 ECR의 URL가 "000000000.dkr.ecr.ap-northeast-2.amazonaws.com/my-image" 였다면, 이미지도 재 태그하여 "000000000.dkr.ecr.ap-northeast-2.amazonaws.com/my-image:<버전테그>" 형식어야합니다. 즉 "/????"의 이름도 같아야합니다.
- name : Push to ECR
env:
AWS_REGION: ${{ secrets.AWS_REGION }}
AWS_ACCOUNT: ${{ secrets.AWS_ECR_ACCOUNT }}
IMAGE_TAG: ${{ github.sha }}
run: |
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com
docker tag my-image:$IMAGE_TAG $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG
docker push $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG
EC2 인스턴스로 SSH 접속: EC2 인스턴스에 접속하기위해서 ".pem"파일의 내용을 sercrets 변수로부터 stdout을 "key.pem"을 작성을 합니다. 이를 이용하여 ssh -i <pem파일경로> 로 접속합니다. 그리고, SSH에 접속후에 ECR로부터 이미지를 pull 받고, 이미 띄워져있는 컨테이너가있다면 중단, 삭제하고, 새로운 이미지를 컨테이너로 구동합니다. 그리고 마지막으로 pem키를 삭제합니다.
- name: SSH into EC2 instance and deploy
env:
AWS_REGION: ${{ env.AWS_REGION }}
AWS_ACCOUNT: ${{ secrets.AWS_ECR_ACCOUNT }}
EC2_USER: ${{ env.EC2_USER }}
EC2_HOST: ${{ env.EC2_HOST }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Create PEM file from encrypted secret
echo "${{ secrets.EC2_PRIVATE_KEY }}" > key.pem
chmod 400 key.pem
# SSH into the EC2 instance and perform deployment
ssh -o "StrictHostKeyChecking no" -i key.pem $EC2_USER@$EC2_HOST \
"sudo docker login -u AWS -p \"$(aws ecr get-login-password --region $AWS_REGION)\" $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com \
&& sudo docker pull $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG \
&& sudo docker stop my-container || true \
&& sudo docker rm my-container || true \
&& sudo docker run -d --name my-container -p 8000:8000 $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG"
# Remove pem
rm key.pem
여기까지 작성했으면, 이제 trigger을 이용하여 action을 실행해볼 차례입니다 .임의의 파일을 수정하여 main에 push하여 tigger을 동작시키면 action화면에 아래와 같이 모든 job 의 실행이 보이게 됩니다.
전체 코드는 아래와 같습니다.
name: Deploy to EC2 with ECR
on:
push:
branches:
- main
EC2_USER: ubuntu
EC2_HOST: <IP>
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to ECR
id: ecr
uses: jwalton/gh-ecr-login@v1
with:
access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
region: ${{ secrets.AWS_REGION }}
- name: Build image
run: |
docker build --tag my-image:$IMAGE_TAG .
- name : Push to ECR
env:
AWS_REGION: ${{ secrets.AWS_REGION }}
AWS_ACCOUNT: ${{ secrets.AWS_ECR_ACCOUNT }}
IMAGE_TAG: ${{ github.sha }}
run: |
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com
docker tag my-image:$IMAGE_TAG $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG
docker push $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG
- name: SSH into EC2 instance and deploy
env:
AWS_REGION: ${{ env.AWS_REGION }}
AWS_ACCOUNT: ${{ secrets.AWS_ECR_ACCOUNT }}
EC2_USER: ${{ env.EC2_USER }}
EC2_HOST: ${{ env.EC2_HOST }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Create PEM file from encrypted secret
echo "${{ secrets.EC2_PRIVATE_KEY }}" > key.pem
chmod 400 key.pem
# SSH into the EC2 instance and perform deployment
ssh -o "StrictHostKeyChecking no" -i key.pem $EC2_USER@$EC2_HOST \
"sudo docker login -u AWS -p \"$(aws ecr get-login-password --region $AWS_REGION)\" $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com \
&& sudo docker pull $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG \
&& sudo docker stop my-container || true \
&& sudo docker rm my-container || true \
&& sudo docker run -d --name my-container -p 8000:8000 $AWS_ACCOUNT.dkr.ecr.$AWS_REGION.amazonaws.com/my-image:$IMAGE_TAG"
# Remove pem
rm key.pem
'Data science > MLOps' 카테고리의 다른 글
pip install -e 옵션에 대해 (0) | 2024.04.02 |
---|---|
[mlflow] child run id 조회하기 (0) | 2023.09.25 |
클러스터 구성 / 쿠버네티스 설치(master, worker node) (0) | 2023.01.08 |
도커 이미지에서 딥러닝 GPU가속 사용하기 (0) | 2022.12.17 |
도커 이미지 푸시하기 (0) | 2022.12.12 |