23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
안녕하세요, dragonpipe입니다.
이 번 게시글 부터 5~6차례에 거쳐서 AKS(Azure Kubernetes Service)를 활용하여 상용 서비스에 API 서버를 띄운 경험에 대해 공유드리려고 합니다.
그 중 첫 번째 글인 이번 포스트 에서는 어떤 기술스택을 활용하였고, 그 중에서도 CI를 구성한 방법에 대해 설명드리겠습니다.
제가 사용하였던 기술 스택은 아래 이미지와 같습니다.
Spring-boot로 개발된 서비스 소스를 Gitlab에 저장하고 Jenkins에서 이 소스를 내려받아서 빌드한 후
결과물인 docker image를 Azure의 컨테이너 저장소인 ACR(Azrue Container Repository)에 저장합니다.
Argocd에서는 ACR에 저장된 이미지를 당겨와 AKS에 배포합니다.
이 때 배포할 리소스(pod, service, ingress 등)에 대한 상세한 내용은 gitlab 특정 프로젝트에 yml 형태로 저장하며,
Jenkins에서 빌드할 때 해당 yml의 컨테이너 이미지 버전 정보를 자동으로 신규 버전으로 변경해주는 방식입니다.
docker 컨테이너를 만드는 다양한 방법이 있지만 (JIB 등) 저는 순수 Dockerfile을 이용해서 이미지를 만들기로 했습니다.
따라서 도커 이미지를 만들 때 필요한 dockerfile을 작성했습니다.
그리고 Jenkins의 빌드 동작을 명시하기 위해 Jenkinsfile을 작성했고 두 파일을 project의 root path에 생성하여 동작할 수 있도록 하였습니다.
이 번엔 젠킨스 파일을 어떻게 작성하였는지 공유드리겠습니다. 그리고 각 라인이 어떤 의미가 있는지 같이 알아보도록 하겠습니다.
우선 제가 작성한 젠킨스 파일은 크게 2개의 stage로 나눠져 있는데요.
첫 번째 stage는 docker container image를 빌드하고 컨테이너 저장소(여기서는 ACR)에 push하는 단계 입니다.
두 번째 stage는 argocd에서 자동으로 컨테이너 이미지 버전의 변경이 있음을 알려주기 위해
manifest 저장소에 저장되어 있는 소스에서 deployment.yml 안에 명시되어 있는 컨테이너 이미지 버전을 변경해주는 단계입니다.
그 중 첫 번째 단계인 docker 컨테이너 이미지를 빌드하고 ACR에 push하는 단계에 대한 상세 설명입니다.
environment variable 설정
credential: acr에 접속할 수 있는 액세스 키 관련 credential ID. (이 credential은 Jenkins에 미리 등록해 놓아야 함.
Credential 추가 방법 아래 이미지 참고)
registry 주소 및 컨테이너 저장소 경로 입력
image명 입력
tag명 입력 : 0.1.{env.BUILD_NUMBER}로 설정하면 자동으로 젠킨스의 빌드 넘버가 tag명으로 설정
withDockerRegistry 함수 작성
위에 정의한 변수로 withDockerRegistry 함수 호출
"계"에 대한 정보(dev/stg/live)는 파라미터로 전달 : ${BUILD_ENV}
Docker Build 명령어 실행할 때 "계"에 대한 정보(dev/stg/live)를 docker에도 arguments로 전달 : –build-arg BUILD=ENV='${BUILD_ENV}'
컨테이너 저장소(예 : ACR)의 Credential ID 입력 (Jenkins에 ACR의 Credential을 미리 등록해 놓아야 함. Credential 추가 방법 아래 이미지 참고)
withDockerRegistry 사용 (Jenkins에 Docker pipeline 플러그인이 젠킨스에 설치되어야 함)
완료 후 jenkins 로컬 서버에 저장된 도커 이미지 삭제 (sh "docker rmi $registry/$image:$tag")
두 번째 단계인 manifest 파일이 저장되어 있는 git에 접속하여 도커 컨테이너 이미지 버전을 변경된 버전으로 수정하는 단계입니다.
environment variable 설정
branch: git에 저장되어 있는 브랜치명명
credentials Id: Jenkins에 미리 생성해 놓은 Credential의 ID
url: Gitlab clone url
중요! gitlab project 저장소에서 access token을 발급받아서 jenkins credential로 생성 필요.
이 때 docker image를 빌드할 원본 소스의 project와 manifest project에 모두 권한이 있도록 상위 프로젝트에서 access token을 발급 받으면 하나의 credential로 처리 가능
WithCredentials 함수 및 Git 명령어 작성
WithCredentials 함수를 사용하여 젠킨스에 저장한 Credential을 마스킹 형태로 사용용
git config 절: git 소스 pull 하는 부분분
sed -i 절: docker image 버전 변경하는 부분 "s/**{image명}**:.*\$/**{image명}**:$tag/g" **{image명}**/deployment.yaml
git add/commit/push 절: 변경한 소스 반영하는 부분
Jenkinsfile 예시시
pipeline {
agent {node{label 'master'}}
stages {
stage("Docker") {
agent{node{label 'master'}}
environment{
credential = {acr관련 jenkins credential ID}
registry = "{acr url}/{image명}/${BUILD_ENV}"
image = "{image명}"
tag = "0.1.${env.BUILD_NUMBER}"
}
steps {
script {
withDockerRegistry(credentialsId: "$credential", url: "https://$registry") {
def img = docker.build("$registry/$image:$tag", "--network host . --build-arg BUILD_ENV='${BUILD_ENV}'")
img.push()
}
sh "docker rmi $registry/$image:$tag" // docker image 제거
}
}
}
stage('K8S Manifest Update') {
environment{
tag = "0.1.${env.BUILD_NUMBER}"
}
steps {
git branch: "main",
credentialsId: "{gitlab accesstoken 관련 credential ID}",
url: "{manifest 파일 저장된 gitlab url}"
withCredentials([usernamePassword(credentialsId: '{gitlab accesstoken 관련 credential ID}', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD')]) {
sh '''
git config --local credential.helper "!f() { echo username=$GIT_USERNAME; echo password=$GIT_PASSWORD; }; f"
sed -i "s/{image명}:.*\$/{image명}:$tag/g" {image명}/${BUILD_ENV}/deployment.yaml
git add {image명}/${BUILD_ENV}/deployment.yaml
git commit -m "[UPDATE] {image명} $tag image versioning"
git push origin main
'''
}
}
post {
failure {
echo 'K8S Manifest Update failure !'
}
success {
echo 'K8S Manifest Update success !'
}
}
}
}
}maven build는 maven:3.8.3-openjdk-17를 base image로 실행
maven run은 메모리를 고려하여 alpine 버전을 base image로 설정 (openjdk:17-alpine)
package -P dev와 Dspring.profiles.active=dev를 통해 "계" 정보 전달
EXPOSE 80 으로 노출 포트 설정
ENTRYPOINT 명령어로 컨테이너 실행 명령어 작성
APM 있을 경우 agent 실행 명령어 추가 : (datadog예시: javaagent:/datadog/apm/agent/dd-java-agent.jar)
"계"에 대한 정보를 "BUILD_ENV"로 전달 받음 (ARG 사용)
ARG 사용할 때 주의할 점
FROM 절 부터 scope이 바뀌므로 FROM 이후에 선언해서 받아야 함!
ARG는 빌드할 때만 사용 가능하고 구동될 때 (CMD 혹은 ENTRYPOINT) 사용 불가
전략 : 빌드할 때 (clean package -P env)는 dockerfile에 정의하고 빌드할 때 active profile은 deployment.yaml 파일에 환경변수로 정의
FROM maven:3.8.3-openjdk-17 AS build
ARG BUILD_ENV
COPY src /home/app/src
COPY libs /home/app/libs
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package -P $BUILD_ENV
FROM openjdk:17-alpine
COPY libs /home/app/libs
COPY --from=build /home/app/target/{docker image명}-0.0.1-SNAPSHOT.jar /usr/local/lib/{docker image명}.jar
EXPOSE 80
ENTRYPOINT ["java","-jar","-javaagent:/datadog/apm/agent/dd-java-agent.jar", "/usr/local/lib/{docker image명}.jar"]new item → pipeline 선택
"이 빌드는 매개변수가 있습니다." 클릭
SCM → git 선택 → Credential 선택
Jenkins 파이프라인 구성에서 Script Path에 "Jenkinsfile" 입력 → 저장
Jenkins 빌드 정상 여부 확인
정상적으로 컨테이너 저장소에 저장되는지 확인
manifest git repo에서 deployment.yaml 파일 이미지 tag 버전 변경되었는지 확인
ACR(Azure Container Repository)와 Jenkins를 활용하여 CI를 구성하는 방법에 대해 알아보았는데요.
이번 CI 구성은 아래와 같은 특징이 있었던 것 같습니다. 아래와 비슷한 경우라면 적용해 보시는 것도 좋을 것 같습니다.
Jenkins를 활용: 기존에 이미 다른 서버 배포를 위해 Jenkins 서버가 구성되어 있어서 사용하게 됨
ACR를 활용: Azure Cloud 서비스를 사용하고 있어 컨테이너 저장소로 ACR를 활용
Dockerfile에 명세: 다른 CI tool로 변경되더라도 (예 : gitlab-runner) 도커 빌드하는 부분은 동일하게 적용할 수 있음
Manifest yml 자동 변경: 빌드한 tag 버전을 자동으로 manifest.git에 있는 yaml 파일에 적용해주므로 ArgoCD에서 자동화 배포 가능
긴 글 읽어주셔서 감사합니다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.