23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
안녕하세요, dragonpipe입니다.
이 번에는 지난 포스트에 이어 AKS(Azure Kubernetes Service) 상용 서비스에 적용한 후기 두 번째 내용으로,
ArgoCD를 활용한 CD(Continueous Deployment) 방법에 대해 소개드리려고 합니다.
ArgoCD는 이미 너무 유명해서 잘 알고 계실거라고 생각하는데요.
구글이나 여러 기술 사이트에 조금만 검색해도 상세한 설명이 쉽게 찾아 볼 수 있어서 따로 설명드리지는 않고 기본 정의만 아래에 추가 하였습니다.
ArgoCD는 Kubernetes 환경에서의 애플리케이션 배포와 관리를 지원하는 도구로, GitOps 원칙에 기반하여 설계되었습니다.
기본적으로 Git 저장소에 기록된 애플리케이션의 상태를 Kubernetes 클러스터와 동기화하는 역할을 수행합니다. 이를 통해 배포의 전체 상태와 변화 과정을 Git을 통해 효과적으로 추적하고 관리할 수 있습니다.
저는 아래와 같은 전략으로 CD를 구성해보았습니다.
argoCD를 통해 ACR에 저장되어 있는 어플리케이션 도커이미지를 k8s에 배포
manifest yaml 파일을 하나의 git repo에서 모두 관리하고 프로젝트는 디렉토리로 구분하여 저장
ArgoCD 등 k8s 관리에 필요한 것들을 서비스하기 위한 클러스터를 별도로 구성 (mgmt cluster). 단, 개발환경(dev/stg/live) 마다 하나씩 존재
어떻게 CD를 구성하였는지 좀 더 자세히 알아보도록 하겠습니다.
우선 manifest 파일 저장을 위해 git repository를 하나 생성하였습니다.
ArgoCD는 위 용어 정의를 보셨다시피 Git 저장소에 기록된 애플리케이션의 상태를 동기화 하도록 되어 있는데요.
따라서 애플리케이션에 대한 상태 정의 파일(manifest)을 저장할 수 있는 repository가 하나 필요합니다.
ArgoCD에서 app을 만들 때마다 git project를 만들면 너무 저장소가 많아 지겠죠..?
그래서 하나의 git repository에 여러개 애플리케이션의 manifest 파일들을 같이 관리하려고 합니다.
이 때 ArgoCD에 app을 정의할 때 이 app이 어떤 애플리케이션인지 또 어떤 환경계(dev/stg/live)인지 알아야 합니다.
이를 위해 아래와 같이 {app명}/{env}으로 네이밍룰을 정해 디렉토리를 생성하였습니다.
어떤 app인지 구분하기 위해 root directory 이름을 app명으로 작성
env(환경계)를 구분하기 위해서 하위 directory 이름을 (dev/stg/live)로 작성
물론 git branch(develop/staging/main)로 구별할 수도 있지만, 다른 환경 파일을 수정할 때마다 브랜치를 스위칭 해주어야 하고
develop, staging, main 브랜치의 파일 내용을 다르게 관리해야 하기 때문에 (merge 하면 안됨) 좋지 않은 방법이라고 생각하여
main 브랜치에 모두 올려놓고 디렉토리 이름(dev/stg/live)으로 구분하도록 하였습니다.
이제 manifest 파일을 알아보도록 하겠습니다.
kubernetes에 app을 띄울 때 helm 방식도 가능하지만 helm으로 관리할 정도로 복잡한 서비스가 아니었기 때문에 필요한 리소스 별로 yml 파일을 작성하여 배포하였습니다.
그 중 가장 중요한 deployment.yaml에 대해 알아보도록 하겠습니다.
특징은 Azure Cloud를 사용하므로 컨테이너 저장소로 ACR을 사용하고 있고 APM으로 Datadog을 사용하고 있습니다.
deployment.yaml 파일 생성
matchLabels.app: 설정 : {app명} 입력
spec.nodeSelect 설정 : "kubernetes.io/os" : linux
container image 설정 : {acr url}/{app명}/{env}/{app명}:{image버전}
resoucrces request/limit 설정
memory의 limit값이 애플리케이션의 max heap size 보다 커야 함 (예 : java의 Xmx 설정)
timezone 설정 : env.name : TZ, value : Asia/Seoul
active profile 설정 : env.name : SPRING_PROFILES_ACTIVE
containerPort 설정 : 컨테이너에서 개발할 포트 번호 (application에서 정한 server.port와 동일해야 함!)
ACR 설정: 원래 imagePullSecrets 설정이 필요하나 아래의 명령어로 AKS cluster에 권한을 부여하면 Secret 필요 없음 (* 주의사항: 같은 구독에 있는 ACR만 접근 가능)
az aks update -n <aks-cluster-name> -g <aks-resource-group> --attach-acr <acr-name>TLS secret volume mount 설정 : TLS secret을 컨테이너 내부로 가져와야 SSL 인증이 정상적으로 수행 (없을 시 PKIX 에러 발생, volumeMounts와 volume 설정 참고)
Datadog 관련 설정
env 추가
DD_AGENT_HOST: Pod가 속한 Node에 DeamonSet으로 deploy된 Datadog Agent로 APM 데이터를 보내기 위해 status.hostIP 를 사용하여 node의 IP를 설정
DD_SERVICE: Datadog APM 에서 보여지는 서비스명으로 metadata의 app 이름으로 설정
DD_ENV: 개발 환경 (dev/stg/live)
DD_TRACE_ENABLED: 각 환경에서 APM 의 사용 여부를 정할 때 사용 (dev는 false로 설정, stg/lives는 true로 설정)
DD_TRACE_SAMPLE_RATE: 수집하는 데이터의 sampling rate을 설정. 1은 100%를 의미
DD_PROFILING_ENABLED: Datadog Continuous Profiler 를 활성화 하는 것으로 매우 낮은 overhead로 code issue나 performance regression을 확인할 수 있음
DD_LOGS_INJECTION: 로그 추적 기능 사용여부 (만약 EFK로만 로그 모니터링을 할 경우 false로 설정)
DD_JMXFETCH_ENABLED: JVM Metrics를 활성화 하기 위해 필요. (문서에는 default 값이 true라고 되어 있지만 명시적으로 이렇게 하지 않으면 JVM Metrics 가 나오지 않으므로 true 설정 필수)
apm agent volume 설정
사전준비사항
azure NAS에 datadog apm agent 실행을 위한 jar파일 업로드
pv, pvc 생성
volume으로 mount
volumes.persistentVolumeClaim.claimName: datadog-pvc
volumeMounts.mountPath: /datadog/apm/agent
apiVersion: apps/v1
kind: Deployment
metadata:
name: {app명}
namespace: {namespace명}
spec:
replicas: 1
selector:
matchLabels:
app: {app명}
template:
metadata:
labels:
app: {app명}
spec:
nodeSelector:
"kubernetes.io/os": linux
containers:
- name: {app명}
image: {acr url}/{env}/{app명}:{버전}
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 400m
memory: 512Mi
ports:
- containerPort: 80
env:
- name: TZ
value: Asia/Seoul
- name: SPRING_PROFILES_ACTIVE
value: dev
- name: DD_AGENT_HOST
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: DD_SERVICE
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']
- name: DD_ENV
value: "dev"
- name: DD_VERSION
value: "1.0"
- name: DD_TRACE_ENABLED
value: "true"
- name: DD_TRACE_SAMPLE_RATE
value: "1"
- name: DD_PROFILING_ENABLED
value: "true"
- name: DD_LOGS_INJECTION
value: "true"
- name: DD_JMXFETCH_ENABLED
value: "true"
volumeMounts:
- name: secret-volume
mountPath: /etc/secret
volumeMounts:
- name: datadog-apm-agent
mountPath: /datadog/apm/agent
volumes:
- name: datadog-apm-agent
persistentVolumeCl
claimName: datadog-pvc
- name: secret-volume
secret:
secretName: trealxyz-tls이번엔 서비스 노출을 위해 필요한 service.yaml도 알아보겠습니다.
service.yaml 파일 작성
service name 설정: 저는 app명 뒤에 -svc를 붙여서 만들었습니다.
selector 설정 : 연결하고자 하는 deployment의 app name으로 설정
ports 설정
protocol : TCP
targetPort : 파드의 애플리케이션 쪽에서 열려있는 포트를 의미. 서비스로 들어온 트래픽은 해당 파드의 <클러스터 내부 IP>:<targetPort>로 넘어가게 됨
port : 서비스 쪽에서 해당 파드를 향해 열려있는 포트를 의미
type : ClusterIP (지정하지 않으면 기본값인 ClusterIP로 설정)
apiVersion: v1
kind: Service
metadata:
name: {service명}
spec:
type: ClusterIP
selector:
app: {app명}
ports:
- protocol: TCP
port: 80
targetPort: 80참고. LoadBalancer Type으로 Service를 띄울 때 고정 IP 사용하는 법
type에 LoadBalancer로 입력 시 LoadBalancer와 Service가 다이렉트로 연결됨 (Ingress일 경우 중간에 Ingress를 거침)
URL기반이 아니라 IP와 PORT로 통신이 필요할 때 설정
LoadBalancer 타입일 경우 Ingress.yaml 파일은 필요 없음
nodePort항목은 입력하지 않으면 자동으로 설정됨 (30000부터 32767까지 가능)
IP를 LB에서 동적으로 할당받지 않고 정적으로 고정하고 싶은 경우 아래와 같이 수행
azure portal에서 public IP address를 하나 생성
생성한 public IP address 정보를 service.yaml의 annotations에 추가
중요! azure portal에서 public IP에 있는 연결(associate) 버튼을 클릭하여 aks의 loadbalancer와 연결하면 node 장애 발생할 수 있으므로 반드시 aks의 yaml 파일에 작성할 것
적용한 뒤 kubernetes service를 재구동(argoCD에서 sync)한 뒤 k get svc로 external IP에 가 할당되었는지 확인
azure portal에서 생성했던 public IP에 kubernetes가 연결(associated)되었는지 확인
annotaion이 추가된 service.yaml 파일
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/azure-load-balancer-resource-group: <node resource group>
service.beta.kubernetes.io/azure-load-balancer-ipv4: <public IP address>
service.beta.kubernetes.io/azure-pip-name: <public IP Name>
name: {service명}
spec:
selector:
app: {app명}
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 32618
type: LoadBalancerHTTP 기반 통신이 필요할 경우 ingress를 추가하여야 하는데요. manifest 파일을 어떻게 작성하였는지 알아보겠습니다.
ingress.yml 파일 작성
kind : Ingress
annotation : kubernetes.io/ingress.class : "nginx" 명시
nginx 관련 annotaion 중 필요한 것 입력 (아래 표 참고)
단, rewrite-tartget은 redirect url 관련 설정인데 입력하면 정상적으로 웹 uri가 전달되지 않으므로 주의가 필요
host : domain url 입력
tls 설정
hosts : 위의 domain url과 동일하게 입력 (대신에 해당 url로 인증서가 미리 설치되어야 함)
secretName : 인증서 설치하면서 생성한 secret의 이름 입력
path : 해당 서비스를 구별할 base uri 입력
pathType : prefix로 입력
service : 연결할 서비스의 이름 입력
port : 서비스로 연결할 때 사용할 포트 번호 입력
http://nginx.ingress.kubernetes.io/rewrite-target | Target URI where the traffic must be redirected | string |
|---|---|---|
http://nginx.ingress.kubernetes.io/ssl-redirect | Indicates if the location section is only accessible via SSL (defaults to True when Ingress contains a Certificate) | bool |
http://nginx.ingress.kubernetes.io/force-ssl-redirect | Forces the redirection to HTTPS even if the Ingress is not TLS Enabled | bool |
http://nginx.ingress.kubernetes.io/app-root | Defines the Application Root that the Controller must redirect if it's in / context | string |
http://nginx.ingress.kubernetes.io/use-regex | Indicates if the paths defined on an Ingress use regular expressions | bool |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {ingress명}
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: {도메인 주소}
http:
paths:
- path: {app uri prefix}
pathType: Prefix
backend:
service:
name: {service명}
port:
number: 80
tls:
- hosts:
- {도메인 주소}
secretName: {tls명}이제 작성한 manifest 파일을 이용하여 AKS에 application을 띄워보도록 하겠습니다.
ArgoCD에서 New App 버튼 클릭 → 설정 값 입력 → Create 버튼 클릭
Git Repository URL과 Cluster 관련 설정 선택
Sync 버튼 클릭 → Syncronize 버튼 클릭
pod 클릭 → Logs 탭 → 정상 로그 확인
sync policy를 manual로 설정하였을 경우 : status가 OutOfSync로 인식되는지 확인하고 sync 버튼을 클릭하여 동기화를 수행
argoCD 에서 sync policy를 auto로 설정하였을 경우 자동 배포되는지 확인 필요 (주기 기본 값 3분)
Ingress와 ingress-controller로 설정한 host(도메인) + base uri(prefix)로 정상 서비스 되는지 확인
이 번 글에서는 ACR(Azure Container Repository)에 저장되어 있는 image를 ArgoCD가 당겨와서 kubernetes에 자동 또는 수동으로 배포하여
정상적으로 서비스 되는 것 까지 확인하는 과정에 대해 알아보았습니다.
api 서비스를 띄울 때 필수인 리소스(deployment, service, ingress)의 manifest yaml 파일에 대해서 소개드렸는데,
다음에는 Optional한 리소스이지만 안정적인 서비스에 매우 도움되는 k8s 리소스들에 대해서도 설명드리도록 하겠습니다.
긴 글 읽어주셔서 감사합니다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.