데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      AKS 상용 서비스 적용기 (1) - Jenkins를 활용한 CI 구성

      dragonpipe 24.07.09
      2,155 9 1
      DEVOTEE 요약
      이번에 블로그 연재를 통해 AKS(Azure Kubernetes Service)를 활용한 상용 서비스 API 서버 구축 경험을 공유하겠습니다. 첫 번째 글에서는 사용한 기술 스택과 CI 구성 방법을 설명드리며, GitLab에 소스를 저장하고 Jenkins로 빌드 후 ACR에 docker image를 저장, ArgoCD로 AKS에 배포 과정을 다룹니다. Jenkinsfile 작성과 Dockerfile을 활용한 이미지 빌드 과정도 상세히 설명합니다.
      DEVOTEE 추천 블로그

      시작하는 글

      안녕하세요, dragonpipe입니다.

      이 번 게시글 부터 5~6차례에 거쳐서 AKS(Azure Kubernetes Service)를 활용하여 상용 서비스에 API 서버를 띄운 경험에 대해 공유드리려고 합니다.

      그 중 첫 번째 글인 이번 포스트 에서는 어떤 기술스택을 활용하였고, 그 중에서도 CI를 구성한 방법에 대해 설명드리겠습니다.


      기술 스택 및 CI/CD 전략

      제가 사용하였던 기술 스택은 아래 이미지와 같습니다.

      image.png

      Spring-boot로 개발된 서비스 소스를 Gitlab에 저장하고 Jenkins에서 이 소스를 내려받아서 빌드한 후

      결과물인 docker image를 Azure의 컨테이너 저장소인 ACR(Azrue Container Repository)에 저장합니다.

      Argocd에서는 ACR에 저장된 이미지를 당겨와 AKS에 배포합니다.

      이 때 배포할 리소스(pod, service, ingress 등)에 대한 상세한 내용은 gitlab 특정 프로젝트에 yml 형태로 저장하며,

      Jenkins에서 빌드할 때 해당 yml의 컨테이너 이미지 버전 정보를 자동으로 신규 버전으로 변경해주는 방식입니다.


      CI 구성 상세 내용

      1. 프로젝트 루트 디렉토리에 Dockerfile과 Jenkinsfile 생성

      docker 컨테이너를 만드는 다양한 방법이 있지만 (JIB 등) 저는 순수 Dockerfile을 이용해서 이미지를 만들기로 했습니다.

      따라서 도커 이미지를 만들 때 필요한 dockerfile을 작성했습니다.

      그리고 Jenkins의 빌드 동작을 명시하기 위해 Jenkinsfile을 작성했고 두 파일을 project의 root path에 생성하여 동작할 수 있도록 하였습니다.

      ci(1).png

      2. Jenkinsfile 작성

      이 번엔 젠킨스 파일을 어떻게 작성하였는지 공유드리겠습니다. 그리고 각 라인이 어떤 의미가 있는지 같이 알아보도록 하겠습니다.

      우선 제가 작성한 젠킨스 파일은 크게 2개의 stage로 나눠져 있는데요.

      1. 첫 번째 stage는 docker container image를 빌드하고 컨테이너 저장소(여기서는 ACR)에 push하는 단계 입니다.

      2. 두 번째 stage는 argocd에서 자동으로 컨테이너 이미지 버전의 변경이 있음을 알려주기 위해

        manifest 저장소에 저장되어 있는 소스에서 deployment.yml 안에 명시되어 있는 컨테이너 이미지 버전을 변경해주는 단계입니다.

      Stage 1. Docker image build and push

      그 중 첫 번째 단계인 docker 컨테이너 이미지를 빌드하고 ACR에 push하는 단계에 대한 상세 설명입니다.

      1. environment variable 설정

        • credential: acr에 접속할 수 있는 액세스 키 관련 credential ID. (이 credential은 Jenkins에 미리 등록해 놓아야 함.

          Credential 추가 방법 아래 이미지 참고)

          ci(2).jpeg

        • registry 주소 및 컨테이너 저장소 경로 입력

        • image명 입력

        • tag명 입력 : 0.1.{env.BUILD_NUMBER}로 설정하면 자동으로 젠킨스의 빌드 넘버가 tag명으로 설정

      2. 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")

      Stage 2. ArgoCD manifest 파일 update

      두 번째 단계인 manifest 파일이 저장되어 있는 git에 접속하여 도커 컨테이너 이미지 버전을 변경된 버전으로 수정하는 단계입니다.

      1. 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로 처리 가능

      2. WithCredentials 함수 및 Git 명령어 작성

        • WithCredentials 함수를 사용하여 젠킨스에 저장한 Credential을 마스킹 형태로 사용용

        • git config 절: git 소스 pull 하는 부분분

        • sed -i 절: docker image 버전 변경하는 부분 "s/**{image명}**:.*\$/**{image명}**:$tag/g" **{image명}**/deployment.yaml

        • git add/commit/push 절: 변경한 소스 반영하는 부분

      3. 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 !'
                          }
                  }
              }
      	}
      }

      3. Dockerfile 작성 (maven 빌드 샘플)

      • 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 사용할 때 주의할 점

        1. FROM 절 부터 scope이 바뀌므로 FROM 이후에 선언해서 받아야 함!

        2. ARG는 빌드할 때만 사용 가능하고 구동될 때 (CMD 혹은 ENTRYPOINT) 사용 불가

        3. 전략 : 빌드할 때 (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"]

      4. Jenkins 파이프라인 생성

      • new item → pipeline 선택

      • "이 빌드는 매개변수가 있습니다." 클릭

        ci(3).png

      • SCM → git 선택 → Credential 선택

        ci(4).png

      • Jenkins 파이프라인 구성에서 Script Path에 "Jenkinsfile" 입력 → 저장

        ci(5).png

      • Jenkins 빌드 정상 여부 확인

        1. 정상적으로 컨테이너 저장소에 저장되는지 확인

          ci(7).png

        2. manifest git repo에서 deployment.yaml 파일 이미지 tag 버전 변경되었는지 확인

          ci(8).png


      마치는 글

      ACR(Azure Container Repository)와 Jenkins를 활용하여 CI를 구성하는 방법에 대해 알아보았는데요.

      이번 CI 구성은 아래와 같은 특징이 있었던 것 같습니다. 아래와 비슷한 경우라면 적용해 보시는 것도 좋을 것 같습니다.

      1. Jenkins를 활용: 기존에 이미 다른 서버 배포를 위해 Jenkins 서버가 구성되어 있어서 사용하게 됨

      2. ACR를 활용: Azure Cloud 서비스를 사용하고 있어 컨테이너 저장소로 ACR를 활용

      3. Dockerfile에 명세: 다른 CI tool로 변경되더라도 (예 : gitlab-runner) 도커 빌드하는 부분은 동일하게 적용할 수 있음

      4. Manifest yml 자동 변경: 빌드한 tag 버전을 자동으로 manifest.git에 있는 yaml 파일에 적용해주므로 ArgoCD에서 자동화 배포 가능

      긴 글 읽어주셔서 감사합니다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      dragonpipe 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기