전 편에서 ACI에 배포 자동화를 구축했다. 이제 더 나아가서 ACI, AKS 두 서비스에 동시에 배포할 수 있도록 구성할 것이다! ACI 배포 구성은 마쳤으므로, AKS 배포 자동화를 알아본다.
ACI, AKS 두 타겟에 deploy하기
[!NOTE] AKS란
cluster를 빠르게 배포하고 관리할 수 있는 관리형 쿠버네티스 서비스.
CLI로 AKS 클러스터 만들기
아래 명령어를 통해 AKS 클러스터를 생성한다. 나는 OsscaDevops-Cluster
라는 클러스터를 생성했다.
az aks create -g <리소스-그룹-이름> -n <클러스터-이름> \
--enable-managed-identity \
--node-count 1 \
--generate-ssh-keys \
"Registration succeeded."라는 문구와 함께 JSON 포맷의 response를 받으면 성공이다.
리소스 그룹에 Kubernetes 서비스라는 형식으로 잘 생성된 것을 확인.
❗ISSUE --enable-addons monitoring
인자 에러
공식 도큐먼트에 기재된 명령어는 아래와 같은데,
--enable-addons monitoring
인자는 Azure Monitor Container insights를 가능하게 하는 옵션이라고 한다.
az aks create -g <리소스-그룹-이름> -n <클러스터-이름> \
--enable-managed-identity \
--node-count 1 \
--enable-addons monitoring \
--generate-ssh-keys \
문제는 저걸 넣어서 실행시켰더니 아래와 같은 에러가 뜬다.
Conflict({"ISSUE":{"code":"MissingSubscriptionRegistration","message":"The subscription is not registered to use namespace 'microsoft.insights'. See https://aka.ms/rps-not-found for how to register subscriptions.","details":[{"code":"MissingSubscriptionRegistration","target":"microsoft.insights","message":"The subscription is not registered to use namespace 'microsoft.insights'. See https://aka.ms/rps-not-found for how to register subscriptions."}]}})
subscription 얘기가 있는 걸로 보아 구독 관련 이슈인 것 같다.
찾아보니 "microsoft.insights"라는 기능을 등록하지 않아서 생기는 문제라고 한다. ‘microsoft.insights’ 네임스페이스에 대한 등록이 필요하다.
Azure에서는 사용자가 특정 서비스를 사용하기 전에 해당 서비스에 대해 구독을 등록해야 한다.
이는 사용자가 원치 않는 서비스에 대한 비용이 청구되는 것을 방지하며, Azure에서 해당 서비스의 사용량을 추적할 수 있게 한다.
Azure 포털 > 구독 > 사용하고 있는 구독 선택 > 리소스 공급자에 접속한다.
검색 창에 'microsoft.insights’를 입력하고, 해당 제공자를 찾은 후 클릭하여 '등록’을 누른다.
우선 나는 이 기능을 등록하지 않고 진행했다.
Kubernetes 명세 파일 작성하기
여기를 참고한다 ☞ Build, test, and deploy containers to Azure Kubernetes Service using GitHub Actions - Azure Kubernetes Service | Microsoft Learn
https://learn.microsoft.com/en-us/azure/aks/tutorial-kubernetes-prepare-app
ACI 뿐만 아니라 이번에는 컨테이너를 활용하는 다른 azure 서비스에도 배포하는 작업을 진행한다.
결과적으로 동시에 두 개소에 자동 배포하는 것이 목표이다.
Azure 도큐멘테이션의 예제 repo (Azure-Samples/azure-voting-app-redis: Azure voting app used in docs. (github.com))의 yaml 파일을 참고하여 아래처럼 수정해보았다. (※ 이후 에러를 해결하면서 일부 수정함)
apiVersion: apps/v1
kind: Deployment
metadata:
name: ossca-devops-app
spec:
replicas: 1
selector:
matchLabels:
app: ossca-devops-app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
minReadySeconds: 5
template:
metadata:
labels:
app: ossca-devops-app
spec:
nodeSelector:
"kubernetes.io/os": linux
containers:
- name: ossca-devops-app
image: osscadevopsimages.azurecr.io/ossca-devops-app:latest
ports:
- containerPort: 80
resources:
requests:
cpu: 250m
limits:
cpu: 500m
---
apiVersion: v1
kind: Service
metadata:
name: ossca-devops-app
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: ossca-devops-app
Github actions file 수정하기
기존에 작성한 main_deploy.yml
파일을 수정하여 AKS 배포 부분도 작성해야 한다.
우선 기존의 deploy 작업을 공식 도큐먼트를 참고하여 아래와 같이 수정하였다.
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Set AKS context
id: set-context
uses: azure/aks-set-context@v3
with:
resource-group: ${{ secrets.RESOURCE_GROUP }}
cluster-name: ${{ secrets.CLUSTER_NAME }}
- name: Setup kubectl
id: install-kubectl
uses: azure/setup-kubectl@v3
- name: Deploy to AKS
id: deploy-aks
uses: Azure/k8s-deploy@v4
with:
namespace: 'default'
manifests: |
ossca-devops.yaml // 쿠버네티스 yml 파일명
images: ${{ secrets.REGISTRY_LOGIN_SERVER }}/ossca-devops-app:${{ github.sha }}
pull-images: false
이 때 CLUSTER_NAME
이라는 secret이 사용되므로 깃헙 시크릿을 생성한다.
공식 문서에 따르면, AKS에 배포하기 위해 아래의 총 6단계를 거친다.
- Checkout source code uses the GitHub Actions Checkout Action to clone the repository.
- ACR build uses the Azure Container Registry Build Action to build the image and upload it to your registry.
- Azure login uses the Azure Login Action to sign in to your Azure account.
- Set AKS context uses the Azure AKS Set Context Action to set the context for your AKS cluster.
- Setup kubectl uses the Azure AKS Setup Kubectl Action to install kubectl on your runner.
- Deploy to AKS uses the Azure Kubernetes Deploy Action to deploy the application to your Kubernetes cluster.
기존 yaml 파일에선 ACI에 배포하기 위해 ACR 빌드하기 전 azure login 단계를 수행한다.
따라서 이미 로그인이 되어 있다고 보고 나는 4~6단계만 포함시켜 주었다.
이제 이 변경사항을 저장소에 반영하여 잘 돌아가는지 (어떤 에러가 날런지 ㅎ) 확인해보자.
❗ISSUE “please run ‘az login’ to setup account.”
아무래도 내 생각이 틀렸던 듯 싶다.
위에서 말한 6단계 중, 3단계를 또 작성해야 하는 것 같다.
build 작업과 deploy 작업은 각기 다른 runner에서 실행된다(ubuntu-latest). 새로운 가상환경에서 실행되므로 각기 로그인을 해주어야 하는 것이 맞는 거 같다.
아니 그런데, 이번에는 github action이 "Waiting for a runner to pick up this job…"이라는 말만 내놓고 아무런 작업이 일어나지 않았다.
스택 오버 플로우(ISSUE “Waiting for a runner to pick up this job” using GitHub Actions - Stack Overflow)에서 운영체제를 제대로 명시했는지를 확인하라고 했고, 이럴수가 …
“runs-on: ubuntu-latests” 라고 작성한 나의 오타를 발견하였다. 😅
고치고 다시 PR을 올리니 해당 단계를 통과한다.
❗ISSUE “no such file or directory, lstat ‘ossca-devops.yaml’”
분명 파일이 존재하는데 또 뭐가 문제일까…
디렉토리를 제대로 찾아가지 못하고 있나 의심이 들었다.
혹시 몰라 <프로젝트-폴더명>/ossca-devops.yaml
로 수정하여 다시 확인였으나 동일한 오류를 내뿜었다.
루트 디렉토리가 어떻게 잡히고 있는 건지 궁금했다.
GPT4가 아래 스텝을 이용해 디렉토리와 파일을 확인해보라는 꿀팁을 주었다.
- name: Check current directory
run: pwd
- name: List files in current directory
run: ls
그래서 deploy 단계에서 해당 스텝을 포함하여 실행해본 바, 루트 디렉토리를 찾아가는 것은 문제가 없는데
아래처럼 ls -a
를 실행하니 아무런 프로젝트 파일이 나타나지 않았다.
꽤 여러 번의 삽질 끝에 원인을 찾아냈다.
저장소 코드를 가상환경으로 복사하는 작업은 uses: actions/checkout@main
을 통해서 일어난다.
즉, 앞서 말한 6단계 중 1단계를 의미한다.
AKS 배포 작업 yaml을 작성하면서, build 작업에서 checkout@main을 진행하니까 한 번 더 할 필요가 없다고 생각했다. ⇒ 새로운 가상환경에서 deploy 작업이 일어나는 것을 간과한 것이다.
더군다나 ACI에 배포하는 작업을 진행할 때는 checkout@main을 진행할 필요가 없었기 때문에 더더욱 간과했다. ⇒ 이 경우는 저장소의 코드를 건드릴 필요 없이 Azure에 저장소에 올라가있는 이미지를 실행만 하면 되는 작업이었기 때문이다.
하여튼 결론적으로 AKS 배포 작업을 하면서 새로운 가상환경을 실행시켰고(build 작업을 진행한 runner가 아닌)
context를 설정하는 작업해서 저장소의 manifest 파일을 이용해야 하기 때문에,
저장소의 코드를 deploy 작업이 일어나는 가상환경으로 복사해야 한다.
그래서 checkout@main이 수행되어야 한다.
최종적으로 위의 6단계 中 2단계를 제외한 나머지를 AKS deploy에서 수행해주었다.
그 결과 프로젝트 파일이 위처럼 잘 복사되었고, manifest 파일도 잘 찾아서 set AKS context 단계를 마무리한 것을 확인했다.
❗ISSUE ‘ossca-devops-app’ 이미지를 찾지 못하는 에러
잘 넘어가나 했는데 아무래도 쿠버네티스 manifest 파일에서 잘못 설정한 부분이 있는 모양이다. (작성하면서 조금 의심스럽긴 했다. )
Azure 포털에서도 아래와 같은 결과를 받았다.
ImagePullBackOff는 쿠버네티스가 도커 이미지를 저장소에서 가져오는데 실패했음을 의미한다.
짐작컨대 이미지 명에서 뭔가 에러가 있었던 것이 틀림없다.
ACR로 달려가서 실행해야 하는 이미지 명을 살펴본다.
이렇게 생겼다.
manifest 파일에서 ossca-devops-app이라고 작성했던 부분을 flaskapp으로 바꿔준다.
그런데 ….
위처럼 flaskapp:해쉬값이 이미지 저장소의 가장 최신 이미지와 일치하는 것을 확인했음에도 동일한 오류가 뜨고 있다.
Azure 포털에서 해당 pod의 이벤트 로그를 살펴보았더니, 에러 메시지 응답에서 아래와 같은 note를 발견할 수 있었다.
Failed to pull image
"osscadevopsimages.azurecr.io/flaskapp:6aae6e91765255fc3142c517dea8c65ebfe3f0c7":
rpc ISSUE: code = Unknown desc = failed to pull and unpack image
"osscadevopsimages.azurecr.io/flaskapp:6aae6e91765255fc3142c517dea8c65ebfe3f0c7":
failed to resolve reference
"osscadevopsimages.azurecr.io/flaskapp:6aae6e91765255fc3142c517dea8c65ebfe3f0c7":
failed to authorize: failed to fetch anonymous token: unexpected status from
GET request to
https://osscadevopsimages.azurecr.io/oauth2/token?scope=repository%3Aflaskapp%3Apull&service=osscadevopsimages.azurecr.io:
401 Unauthorized
마지막에 401 Unauthorized가 눈에 띈다.
AKS가 ACR에 접근하기 위한 자격증명이 문제인 것일까?
아래 다음 명령어를 통해 AKS의 클러스터가 ACR에 접근해 이미지를 받아올 수 있는 권한을 부여하자.
az aks update -n <클러스터-이름> -g <리소스-그룹명> \
--attach-acr <ACR-name>
우선 동일한 에러는 나지 않는 것을 확인했다.
❗ISSUE AKS CrashLoopBackOff
그러나 이번에는 또 다른 에러!
CrashLoopBackOff 상태는 쿠버네티스에서 파드가 반복적으로 실패하고 재시작을 시도하는 상황을 의미한다고 한다.
파드의 컨테이너가 시작되지 않거나 시작 후 바로 종료되는 경우라는데, 일반적으로 애플리케이션 코드의 문제, 컨테이너 이미지의 문제, 잘못된 컨테이너 구성, 부적절한 리소스 할당 등 다양한 원인으로 인해 발생할 수 있다고 한다.
지금 내 코드는 단순 문자열 출력 후 종료되는 프로그램이라서 그런 걸까?
이 점도 그렇고, 일단 서버를 띄워서 외부 IP로 접속이 되는지 확인할 필요도 있었기 때문에 제대로 된 flask 보일러 플레이트 코드를 다음과 같이 작성하여 app.py에 업데이트 했다.
# Import the Flask module that has been installed.
from flask import Flask
# Creating a new "app" by using the Flask constructor. Passes __name__ as a parameter.
app = Flask(__name__)
# Annotation that allows the function to be hit when the specific HTTP request is performed.
@app.route('/')
def home():
return 'index page'
@app.route('/hello')
def hello():
return {"msg": "hello, ossca"}
# Main driver function
if __name__ == '__main__':
# run() method of Flask class runs the application
# on the local development server.
# app.debug = True
app.run(host='0.0.0.0', port='5000') # host를 0.0.0.0으로 지정해줘야 외부 접근 가능
이제 github action 상의 deploy 오류는 해결되었다! 짝짝짝.
하지만 또 동일한 CrashLoopBackOff 쿠버네티스 오류가 발생했다.
왜 컨테이너가 종료되는지 컨테이너 터미널 로그를 확인하고 싶었다. Azure cli로 pod 로그를 확인하는 방법을 아래와 같이 찾았다.
- 먼저
az aks get-credentials
명령을 사용하여 클러스터에 연결한다. 이 명령은~/.kube/config
파일에 쿠버네티스 클러스터에 대한 접속 정보를 저장한다.
az aks get-credentials --resource-group <your-resource-group> --name <your-cluster-name>
kubectl
명령을 사용하기 위해 설치부터 하고,
sudo az aks install-cli
- 문제가 일어난 파드의 이름과 네임스페이스를 입력하고 로그를 확인해본다.
kubectl logs <pod-name> -n <namespace>
아뿔싸. 모듈 설치를 안 해주었구나 … ^^
일단 임시방편으로 도커 파일에 flask
모듈을 설치하는 명령어를 작성했다.
"Running"이라는 반가운 초록불이 떴다. 🙌
❗ISSUE: 외부 접속 불가
참고 ☞ Service | Kubernetes
자, 이제 방금 쿠버네티스로 띄운 flask 앱에 접속해 hello ossca
를 잘 보여주는지 확인할 차례만 남았다.
네트워크와 관련된 부분은 쿠버네티스의 "Service"라는 기능에서 찾아보면 된다. (쿠버네티스 스터디에서 배움✌️)
대시보드에 접속하면 여러 가지 네트워크 정보들이 보인다.
느낌상 외부 IP에 접속하면 되지 않을까? 해서 클릭했지만, 접속되지 않는다.
또 뭔가가 잘못되었다!
제일 먼저 의심이 가는 것은 포트 문제이다.
flask 앱은 디폴트로 5000번 포트로 지정되어 있다. 반면 쿠버네티스 manifest에는 80번 포트를 쓰겠다고 명시되어 있다.
사실 문제가 될 것 같다는 의심을 했지만 에러 났을 때 확실히 알아보려고 일단 진행했었다.
요 문제를 한 번 파헤쳐보자.
우선 기존의 쿠버네티스 manifest 파일에서 포트 부분을 살펴보면, 아래 두 군데에서 언급하고 있다.
...
kind: Deployment
...
spec:
nodeSelector:
"kubernetes.io/os": linux
containers:
- name: flaskapp
image: osscadevopsimages.azurecr.io/flaskapp:latest
ports:
- containerPort: 80
...
---
apiVersion: v1
kind: Service
...
spec:
type: LoadBalancer
ports:
- port: 80
...
이 부분을 건드리면 될 것 같다는 느낌이 온다.
그런데 서비스의 세부 정보를 살펴보면 아래와 같은 항목들을 볼 수 있다.
형식: LoadBalancer
클러스터 IP: 10.0.155.51
외부 IP: 20.196.242.36
nodeport: 32055
port: 80
protocol: TCP
대상 포트: 80
endpoint: 10.244.0.21:80
“노드 포트”, “포트”, “대상 포트” 이 세 가지 포트를 언급하고 있는 것을 알 수 있다.
난 도대체 어떤 포트를 건드려야 하는 걸까? 궁금해졌다.
특히 "포트"와 "대상 포트"의 차이가 무엇인지 모르겠다.
한번 개념을 정리하고 갈 필요가 있을 것 같아서 알아보았다.
- “형식(Service Type): LoadBalancer”:
- 이는 서비스의 유형을 나타낸다
- LoadBalancer 유형의 서비스는 쿠버네티스 클러스터 외부에서 접근 가능한 공개 IP 주소를 할당받는다
- 클라우드 제공 업체(내 경우 Azure)의 로드 밸런서를 사용하여 서비스에 대한 트래픽을 적절한 파드로 분산시킨다
- “클러스터 IP: 10.0.155.51”:
- 이는 쿠버네티스 클러스터 내부에서만 접근 가능한 IP 주소
- 마치 사무실 내부 전화 시스템과 같은 것으로, 사무실 내에서는 특정 번호(예: 내선 번호)만으로 서로 통화를 할 수 있지만, 이는 사무실 바깥에서는 접근할 수 없는 방식이다.
- 예를 들어, 웹 애플리케이션과 데이터베이스가 동일한 클러스터 안에 있고 웹 애플리케이션이 데이터베이스에 연결해야하는 경우에 Cluster IP를 사용하게 된다. 웹 애플리케이션은 데이터베이스 서비스의 Cluster IP와 포트를 통해 데이터베이스에 접속하게 된다.
- “외부 IP: 20.196.242.36”:
- 이는 클러스터 외부에서 서비스에 접근할 수 있도록 하는 IP 주소
- 이는 공용 전화번호와 같은 것. 누구나 이 번호를 통해 특정 사람이나 부서에 전화를 걸 수 있다.
- 예를 들어, Kubernetes 클러스터에 배포된 웹 사이트에 사용자가 접속하려면 외부 IP를 통해 접속하게 된다. 이 때 사용자는 웹 브라우저에서 외부 IP 주소(또는 해당 IP와 맵핑된 도메인 이름)를 입력하게 된다.
- “NodePort: 32055”:
- 클러스터의 모든 노드에서 동일한 포트로 서비스를 노출한다
- 외부에서 직접 노드에 접속해야 할 때 사용한다. 예를 들어, 특정 보안 규정 때문에 로드밸런서나 Ingress를 사용하지 않고, 직접 노드에 접속해야 하는 경우. 이 때 사용자는
http://<노드의 IP>:<노드포트>
를 통해 서비스에 접속하게 된다. 이러한 경우가 일반적이지는 않다고 함.
- “port: 80”:
- 서비스가 자신에게 오는 트래픽을 받아들이는 포트. Service Port.
- 클러스터 내부나 외부에서 특정 서비스에 접근하기 위해 사용된다. 예를 들어, 웹 애플리케이션이 80 포트를 사용하도록 설정되어 있다면, 사용자는 웹 브라우저에서
http://<외부 IP>:80
를 통해 웹 애플리케이션에 접속하게 된다.
- protocol: TCP: 서비스가 사용하는 프로토콜로, TCP가 디폴트 프로토콜이다. (☞ 지원하는 다른 프로토콜 종류 Protocols for Services | Kubernetes)
- 대상 포트(Target Port): 80:
- 이는 서비스가 자신에게 온 트래픽을 전달할 파드의 포트(Pod’s port) 로, 어떤 Pod의 어떤 포트로 요청을 전달해야 하는지를 결정하는데 사용한다.
- 예를 들어, 웹 애플리케이션을 실행하는 Pod가 5000 포트에서 동작하도록 설정되어 있다면, 서비스의 대상 포트는 5000으로 설정된다.
- endpoint: 10.244.0.21:80:
- 엔드포인트는 서비스가 트래픽을 전달할 대상
- 여기서는 IP 주소가 10.244.0.21이고 포트가 80인 파드를 대상으로 한다
- 여기에는 서비스의 선택자에 매치되는 모든 파드의 IP 주소와 포트가 포함될 수 있다
위 사항 중, 내가 쿠버네티스 manifest로 변경하거나 지정할 수 있는 사항은
- Service Type:
LoadBalancer
,NodePort
,ClusterIP
등 서비스의 타입 - Port (Service Port): 서비스가 외부로 노출하는 포트
- Target Port (Pod’s port): 서비스가 요청을 전달할 Pod의 포트
- NodePort: 서비스 타입이
NodePort
로 설정된 경우, 특정 노드 포트를 직접 지정할 수 있다. 하지만 대부분의 경우 Kubernetes가 자동으로 노드포트를 할당한다. (default: 30000-32767)
다음의 내용은 직접 지정하거나 변경할 수 없다:
- Cluster IP: 서비스를 생성하면 Kubernetes 시스템이 자동으로 할당
- External IP: 로드밸런서 또는 Ingress 컨트롤러를 사용하는 경우 클라우드 제공업체(AWS, Google Cloud, Azure 등)가 자동으로 할당
그럼 여기까지 공부하고 다시 아래의 서비스 설정을 살펴본다면,
형식: LoadBalancer
클러스터 IP: 10.0.155.51
외부 IP: 20.196.242.36
nodeport: 32055
port: 80
protocol: TCP
대상 포트: 80
endpoint: 10.244.0.21:80
여기서 "대상 포트"가 80번이 되면 안되고, flask app이 사용하는 5000번 포트로 지정되어야 제대로 작동하겠구나라는 걸 알 수 있다.
port(서비스 포트)는 건드릴 필요가 없을 것이다. “외부IP:서비스포트” 로 접속한 클라이언트의 요청을 Service가 5000번 포트를 사용하는 flask 앱 컨테이너로 보내주기만 하면 되기 때문.
자, 그러면 대상 포트를 5000으로 맞춰주기 위해서는 어떻게 해야 할까?
아까 manifest 파일에 port
말고도 containerPort
라는 필드도 존재했다. 여기에 더불어 kind: Service
의 ports
필드에 targetPort
필드를 추가하여 대상 포트를 지정할 수 있다. 바로 아래처럼.
...
kind: Service
...
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 5000 # 여기
...
containerPort
와 targetPort
두 가지 필드에 대해 정리하면 아래와 같다.
containerPort
: 선택사항. 컨테이너가 이 포트에서 수신을 대기하고 있다고 명시적으로 표현하는 것. 작성하지 않으면 쿠버네티스는 해당 컨테이너가 몇 번 포트에서 수신 대기 하고 있는지 알 수 없다.targetPort
: 선택사항. 작성하지 않으면 자동으로port
의 값을 참조한다고 함. (Service | Kubernetes)
결론적으로 둘 중 하나는 꼭 제대로 작성해야 한다는 말이 된다~!
쿠버네티스 공식문서 (Service | Kubernetes)를 참고하여 아래처럼 포트 설정을 완료했다.
...
kind: Deployment
...
spec:
nodeSelector:
"kubernetes.io/os": linux
containers:
- name: flaskapp
image: osscadevopsimages.azurecr.io/flaskapp:latest
ports:
- containerPort: 5000 # flask 앱의 디폴트 포트로 변경 (추후 ACI 이슈 때문에 80으로 변경)
name: flask-app # name을 지정하여 변수처럼 사용
...
---
apiVersion: v1
kind: Service
...
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: flask-app # flask-app으로 대상 포트 지정
...
대시보드에서 확인하니 아래와 같이 대상 포트가 변경된 것을 확인할 수 있고,
외부 IP로 접속했을 때 성공 메시지가 뜨는 것을 확인했다. 만세~! 🙌🙌
AKS, ACI 두 개 소 배포할 때 조심해야 할 점!! (ACI 포트 매핑)
이제 ACI, AKS 두개소에 동시 배포 하기 위해 deploy를 위한 github actions yml 파일에서 ACI 배포하는 부분을 주석 해제한다.
여기서 조심해야 할 점
- job 네이밍이 중복되면 안 된다는 점이다.(이 부분 때문에 에러를 겪었다.)
deploy-to-ACI
,deploy-to-AKS
이런 식으로 네이밍을 해줬다. - ACI도 포트 설정을 해줘야 한다. (디폴트로는 80으로 지정되어 있다고 한다. 공식문서 참고.)
문제는 github action workflow 파일에서 지정하는 방법을 찾아보려고 했는데, 찾지 못했다.
그래서 도커파일에expose 5000
명령어를 추가했으나… 여전히 디폴트 포트인 80으로 열린다. 🤔
공식문서(Troubleshoot common issues - Azure Container Instances | Microsoft Learn)의 트러블슈팅을 참고하니, "Azure Container Instances doesn’t yet support port mapping like with regular docker configuration."라는 문구가 있었다. 일반적인 도커 설정을 통한 포트 매핑을 지원하지 않는다고 한다. (ACI는 간단한 테스트 목적으로 빠르게 앱을 띄우는 것이 목적인 서비스라서 그런 것 같다.)
그래서 아래처럼 Azure CLI를 통해 환경 변수를 넘겨줌으로서 포트 매핑을 할 수 있다고 전했는데, 문제는 그렇게 되면 배포 시마다 해당 명령어를 입력해줘야 하므로 자동 배포가 아니게 된다.
az container create --resource-group myResourceGroup \
--name mycontainer --image mcr.microsoft.com/azuredocs/aci-helloworld \
--ip-address Public --ports 9000 \
--environment-variables 'PORT'='9000'
그래서 제일 빠른 방법이자 유일한 방법은 flask 앱의 디폴트 포트를 80으로 바꿔주는 방법이었다! (진작에 이렇게 했다면 사실 AKS 포트 지정 삽질을 할 필요가 없었지만)
잘 뜨는 것을 확인하였다. yeah~~~ (한편 ACI는 무료로 영문 DNS를 지정해줘서 사용하기 편하다.)
마지막으로, 아까 건드렸던 AKS 배포를 위한 쿠버네티스 manifest 파일에서 containerPort
를 80
으로 다시 지정하면
AKS에서도 잘 뜨는 것을 볼 수 있다.
마치며
이로서 DevOps 여정을 마친다!
이제 다음 과제는 MLOps이다 😎