🍀 Cloud Architect/Azure

[프로젝트] Azure ACI 배포하기 (with. Docker)

나리 집사 2023. 11. 8. 23:59

0. Docker Config

docker test를 하기 위해 docker 환경 설정을 해준다. 

나는 VMware Workstation에서 환경설정을 진행했다.

 

1. VM에서 환경 구성 (ubuntu-20.04 live server)

2. Docker 다운로드

#docker 설치 스크립트 다운로드
$ curl -fsSL https://get.docker.com -o get-docker.sh

# 스크립트 실행
$ sh get-docker.sh

# 스크립트 실행
$ chmod 777 get-docker.sh
$ ./get-docker.sh

3. Docker 실행

$ systemctl enable --now docker
$ systemctl status docker | grep -i active

# docker0 IP 확인
$ ip add

$ systemctl restart docker

 

1. App Dockerize

먼저, Repository에서 Docker branch를 만든다.

이후 Dockerfile을 작성한다.

FROM 기반이 될 이미지(ex. OS)를 지정 FROM <이미지>
MAINTAINER 작성자의 정보를 기록 MAINTAINER <작성자 <메일>>
COPY 도커 컨테이너의 경로로 파일을 복사합니다 COPY <복사 할 파일 경로> <컨테이너 경로>
WORKDIR 실행 기준 디렉토리 WORDIR <이동할 경로>
RUN FROM의 기반 이미지 위에서 실행될 명령어 RUN <명령어>
ENV 도커의 환경변수를 설정 ENV <환경변수 이름> <값>
EXPOSE 연결할 포트 번호를 명시 EXPOSE <포트 번호1> ...
CMD 컨테이너 시작 이후, 컨테이너에서 실행될 파일 CMD <실행파일> <매개변수1> ...
# Dockerfile

FROM python:3.10
LABEL maintainer="DahyeonWoo <wdh112139@gmail.com>"

COPY . /app
WORKDIR /app

RUN pip install -r requirements.txt

EXPOSE 80

CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "80"]

 

도커를 빌드해 도커 컨테이너를 생성하기 위한 이미지를 생성한다.

# docker build -t 이미지명 .
$ docker build -t hi-world-app .

만든 이미지를 확인할 수 있다.

 

컨테이너 실행 방법은 다음과 같다.

# 생성 및 실행
# docker run --name 컨테이너명지정 -d -p 9090:80 이미지이름
$ docker run --name first-container -d -p 9090:80 hi-world-app

# 실행 확인 후 종료
$ docker stop first-container

 

docker run (<옵션>) <이미지 식별자> (<명령어>) (<인자>)

  • --name 컨테이너명 설정
  • -d 백그라운드 실행
  • --rm 일회성 사용 -> 중지하고 나면 모든 리소스 삭제
  • -p 호스트와 컨테이너 간의 포트 바인드에 사용
    ex) 9090:80 -> 컨테이너 내부에서 80으로 포트 리스닝을 하고 있고 컴퓨터 9090에서 접속 가능하다.

 

2. Azure Cloud Basic

먼저, Azure 체험 계정을 만든다.

무료 학생 계정: https://azure.microsoft.com/ko-kr/free/students

무료 일반 계정: https://azure.microsoft.com/ko-kr/free

 

1) Azure Resource Group 만들기

Azure 리소스 그룹은 리소스(자원) 관리의 기본 단위이다. 리소스를 만들기 위해서는 설정을 해주어야 한다. 리소스에는 가상 머신, 계정, SQL 데이터베이스 등을 포함시킬 수 있다. 자원을 그룹화하여 권한 및 액세스 제어가 편해지고 비용을 효과적으로 관리할 수 있다.

Azure > 리소스 그룹에서 리소스 그룹을 생성한다.

 

2) Container Registry 생성

Azure에서 Docker container와 image를 관리하기 위해서는 Azure의 Container Registry를 생성해야 한다.

Azure > 모든 서비스 > 컨테이너 레지스트리에서 컨테이너 레지스트리를 만든다.


위와 같이 만들었다.

 

3) Shell 설정

Azure CLI 설정

github에 Azure 정보를 등록하려면 Azure 정보를 확인해야 하는데 CLI를 이용하는 방법과 클라우드 자체의 Shell을 사용하는 방법이 있다.

나는 Ubuntu에 Azure CLI를 설치할 것이다. 공식문서를 참고한다.

$ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

 

Azure CLI 팀에서 유지 관리하는 스크립트를 사용해서 모든 설치 명령을 한 단계로 실행한다.

CLI에서 Azure에 로그인을 한다.

$ az login
# https://microsoft.com/devicelogin에서 코드 입력

 

Azure Cloud Shell

페이지 상단의 Shell 버튼을 클릭하여 실행할 수 있다.

 

4) Azure 인증을 위한 자격 증명 만들기

공식문서를 읽고 CSP의 절차대로 credential을 생성하고 secret에 추가해볼 것이다.

 

Resource Group ID를 얻어온다.

$ groupId=$(az group show \
  --name <resource-group-name> \
  --query id --output tsv)

 

<resource-goup-name>에 만든 리소스 그룹 이름을 넣으면 정상적으로 동작한다. (<> 빼고 입력)

 

그런데 나는 에러도 뜨지 않고, 제대로 변수가 저장되지 않는 문제가 있었다. 그래서 일단은 다음과 같은 명령어로 groupId를 직접 확인하고 아래 코드에서 직접 입력했다.

$ az group list

역할을 만든다.

$ az ad sp create-for-rbac \
  --name githubactions \
  --scope $groupId \
  --role Contributor \
  --sdk-auth

실행하면 다음과 같은 JSON 파일을 얻을 수 있다. 결과값들을 저장해둔다.

{
  "clientId": "",
  "clientSecret": "",
  "subscriptionId": "",
  "tenantId": "",
  "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
  "resourceManagerEndpointUrl": "https://management.azure.com/",
  "activeDirectoryGraphResourceId": "https://graph.windows.net/",
  "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
  "galleryEndpointUrl": "https://gallery.azure.com/",
  "managementEndpointUrl": "https://management.core.windows.net/"
}

 

3. Workflow

이제는 컨테이너를 Azure에 자동배포하는 Workflow를 생성해볼 것이다.

 

Github에서 앱 배포에 필요한 SecretValue를 관리하기 위해 다음 탭으로 이동한다. (Settings > Security > Secrets and variables > Actions).

아래와 같은 값을 등록한다.
AZURE_CREDENTIALS The entire JSON output from the service principal creation step
REGISTRY_LOGIN_SERVER The login server name of your registry (all lowercase). Example: myregistry.azurecr.io
REGISTRY_USERNAME The clientId from the JSON output from the service principal creation
REGISTRY_PASSWORD The clientSecret from the JSON output from the service principal creation
RESOURCE_GROUP The name of the resource group you used to scope the service principal

 

Workflow 파일은 다음과 같이 작성했다.

name: python app deployment to ACI

on:
    push:
      branches: [ "main" ]
    pull_request:
      branches: [ "main" ]

jobs:
    build:
        runs-on: ubuntu-latest
        steps:
        # checkout the repo
        - name: 'Checkout GitHub Action'
          uses: actions/checkout@main
          
        - name: 'Login via Azure CLI'
          uses: azure/login@v1
          with:
            creds: ${{ secrets.AZURE_CREDENTIALS }}
        
        - name: 'Build and push image'
          uses: azure/docker-login@v1
          with:
            login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            username: ${{ secrets.REGISTRY_USERNAME }}
            password: ${{ secrets.REGISTRY_PASSWORD }}
        - run: |
            docker build . -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/pythonapp:${{ github.sha }}
            docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/pythonapp:${{ github.sha }}

    deploy:
        needs: build
        runs-on: ubuntu-latest
        steps:
        - name: 'Login via Azure CLI'
          uses: azure/login@v1
          with:
            creds: ${{ secrets.AZURE_CREDENTIALS }}

        - name: 'Deploy to Azure Container Instances'
          uses: 'azure/aci-deploy@v1'
          with:
            resource-group: ${{ secrets.RESOURCE_GROUP }}
            dns-name-label: ${{ secrets.RESOURCE_GROUP }}${{ github.run_number }}
            image: ${{ secrets.REGISTRY_LOGIN_SERVER }}/flaskapp:${{ github.sha }}
            registry-login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
            registry-username: ${{ secrets.REGISTRY_USERNAME }}
            registry-password: ${{ secrets.REGISTRY_PASSWORD }}
            name: aci-pythonapp
            location: 'korea central'

 

Error: Error: The subscription is not registered to use namespace 'Microsoft.ContainerInstance'. See https://aka.ms/rps-not-found for how to register subscriptions.

위와 같은 에러가 발생하는 이유는, 아직 컨테이너 인스턴스 서비스를 구성하지 않았기 때문이다.

 

Azure 홈 > 컨테이너 레지스트리 > 리포지토리에서 앱이 빌드되고 저장소 푸시까지 된 것을 확인할 수 있다.

이제 컨테이너 인스턴스 서비스를 구성해보자.

 

4. Azure Container Instances

공식문서를 참고한다. ACI란 도커 컨테이너를 빠르고 간편하게 실행할 수 있게 해주는 서비스이다. 서버리스 컴퓨팅의 한 형태로, 컨테이너를 실행하기 위한 가상 머신이나 서버를 직접 관리할 필요가 없다. 작업을 빠르게 시작하고 종료할 수 있다.

 

ACI를 등록하기 위해 CLI를 이용해보았다. 아래와 같은 명령어를 입력해서 컨테이너를 만들어보자.

$ az container create \
  --resource-group <resource-group-name> \
  --name <container-name> \
  --image <acrLoginServer>/<conatiner-name>:v1 \
  --cpu 1 \
  --memory 1 \
  --registry-login-server <acrLoginServer> \
  --registry-username <service-principal-ID> \
  --registry-password <service-principal-password> \
  --ip-address Public \
  --dns-name-label <aciDnsLabel> \
  --ports 80

명령어가 성공하면 인스턴스를 하나 만들고, 성공하지 않더라도 ContainerInstance 서비스를 클라우드에 등록할 수 있다.

 

이제 Github Action으로 Deploy가 제대로 되는지 확인해보자.

모든 테스트를 통과한 것을 확인할 수 있었다.

 

Container Instance가 배포된 것도 확인하였다!

# 아래 명령어를 입력하면 컨테이너 DNS를 알 수 있고 웹 페이지를 띄우도록 했다면 확인할 수 있다. 
$ az container show \
  --resource-group <리소스-그룹-이름> \
  --name <컨테이너-인스턴스-이름> \
  --query ipAddress.fqdn

# 로그 확인
$ az container logs \
  --resource-group <리소스-그룹-이름> \
  --name <컨테이너-인스턴스-이름>

 

Azure에서 자동으로 할당하는 DNS 주소로 접속도 가능하다.

 

이렇게 메인 브랜치에 push하면 코드 문법을 확인하고, 자동으로 컨테이너를 배포하는 자동화 파이프라인을 구축할 수 있었다. 

 

자동 배포가 꼭 좋은 것일까? 아니다. 수동 배포를 한다면 릴리즈 프로세스를 신중하게 관리할 수 있다. Build - Docker registry 까지만 수행하고 Deploy는 사람이 확인 후에 배포하는 방식으로 프로젝트를 구성할 수도 있을 것이다.