Gitlab에서 CI/CD하기 (ECR / EKS 연동)

Moondy·2022년 12월 1일
1
post-thumbnail

🔖 요구사항

  1. package - maven으로 jar 파일 빌드
  2. docker_build - Docker image로 빌드한 후 ECR(Elastic Container Registry)에 푸시
  3. deploy - EKS(Elastic Kubernetes Service)에 Pod로 배포

0. (사전 조건) Gitlab pipeline을 위한 config 파일 생성

1. Package

Spring Boot를 사용하고 있다면 jar 파일로 빌드 하는 과정이 필요하다. 이번 프로젝트는 maven을 사용하기 때문에 maven으로 빌드하는 내용만 다룬다. gragle을 사용하는 경우 그에 맞게 image와 script를 수정해서 사용하면 된다.

.gitlab-ci.yml 작성

.gitlab-ci.yml에 다음과 같이 코드를 추가한다.

stages:
  - package
 
package:
  image: adoptopenjdk/maven-openjdk11
  stage: package
  script:
    - 'mvn -B package --file pom.xml'
  artifacts:
    paths:
      - target/*.jar
  only:
    variables:
      - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  • stages: 앞으로 진행할 스테이지들을 나열한다. 지금은 package만 있지만 추후 다른 스테이지를 추가할 예정이라 사용.
  • package: 패키지 단계
  • image: jar 파일을 빌드할 도커 이미지(환경).
  • script: jar 파일을 빌드하는 명령어
  • artifacts: 실행한 결과를 저장(archive). Job 수행 끝나고 artifacts로 저장한 결과를 따로 다운로드할 수 있으며, 다음 stage에서 jar파일을 사용해야하기 경로를 지정해 저장했다.
  • only: stage가 실행되는 조건. default 브랜치에 commit 할 때만 실행하도록 조건을 설정.

2. Docker build

package 단계에서 빌드한 jar 파일을 실행하는 Docker Image를 빌드한 후 Docker Container Registry에 푸시한다. 이 글에서는 ECR에 연동하는 내용만 다룬다.

만약 기본 도커 레포지토리를 사용한다면 공식문서를 참고해서 docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY 방법을 사용하면 된다.

⭐️사전 조건⭐️

(예시)

FROM adoptopenjdk:11-jre-openj9
ADD /target/[파일명].jar [파일명].jar
ADD [설정파일경로].yml application.yml
ENV JAVA_OPTS=""
ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","/[파일명].jar", "--spring.profiles.active=default"]
EXPOSE 8281
  • AWS에서 Access Token 생성하기
    IAM > Access Management > Users > Security Credentials 페이지로 이동해서 Access Key를 생성한다.

  • Variable에 다음과 같이 AWS CLI 로그인을 위한 정보를 저장해놔야한다.
    AWS에서 만든 Access Key를 Gitlab에 등록한다.
    Settings > CI/CD > Variables에 가서 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY를 등록한다.
    options는 콘솔에 민감정보가 뜨지 않도록 Masked는 활성화하되, proted branch 외에 다른 브랜치(feature 브랜치 등)에서도 CI/CD 테스트를 해야해서 Protected 는 비활성화 했다.

.gitlab-ci.yml 작성

variables:
  DOCKER_REGISTRY: 000000000000.dkr.ecr.ap-northeast-2.amazonaws.com
  AWS_DEFAULT_REGION: ap-northeast-2
  APP_NAME: [app-name]
  DOCKER_HOST: tcp://docker:2375
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""

stages:
  - package
  - build
  
package:
  image: adoptopenjdk/maven-openjdk11
  stage: package
  script:
    - 'mvn -B package --file pom.xml'
  artifacts:
    paths:
      - target/*.jar
  only:
    variables:
      - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      

docker_build:
  image: docker:latest
  stage: build
  services:
    - docker:19-dind
  before_script:
    - apk add --no-cache curl jq python3 py3-pip
    - pip install awscli
    - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $DOCKER_REGISTRY

  script:
    - docker build -t $DOCKER_REGISTRY/$APP_NAME:$CI_PIPELINE_IID -t $DOCKER_REGISTRY/$APP_NAME:latest .
    - docker push $DOCKER_REGISTRY/$APP_NAME:$CI_PIPELINE_IID
    - docker push $DOCKER_REGISTRY/$APP_NAME:latest
  only:
    variables:
      - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

variables

  • DOCKER_REGISTRY: AWS의 ECR 주소
  • AWS_DEFAULT_REGION: ECR 리전 위치
  • APP_NAME: 레지스트리에서의 앱 이름
  • DOCKER_HOST/ DOCKER_DRIVER/ DOCKER_TLS_CERTDIR: docker 내에서 docker 서비스(Docker in Docker)를 사용할 수 있도록 하는 기본 설정. (여기선 Default 설정을 사용)
    • 설정을 안하면 Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running? 에러가 뜬다.

services

  • docker:19-dind: before_script 부분에서 AWS에 로그인하기 위해 Docker in Docker 사용한다는 의미

before_script

  • apk add --no-cache curl jq python3 py3-pip: awscli 및 awscli 자체에 대한 사전 요구 사항을 설치
  • aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $DOCKER_REGISTRY: aws cli 로그인 및 ECR 인증

script

  • docker build ~ : 도커 이미지 build. (최상단에 Dockerfile이 있어야 실행된다)
  • docker push ~ : 도커 이미지 푸시

3. Deploy to EKS

EKS(Elastic Kubernetes Service)에 Pod로 배포하는 단계. Gitlab에서 EKS Cluster와 연동하려면 Gitlab Agent를 설치해야한다. 예전에는 Authentication Token등으로 인증하기도 했던것 같은데, deprecated 되어서 Agent를 설치하는 방법을 선택했다.

(사전 조건) Gitlab Agent 설치 및 EKS 연결

참고 자료: gitlab 공식문서
EKS와 EKS에 연동된 aws-cli가 있어야 한다. 생성방법은 AWS 공식문서 참고

## 사전 조건 summary
1. gitlab repository에 gitlab agent configuration 파일 생성
2. gitlab에 Kubernetes Cluster 등록
3. kubernetes cluster에 gitlab agent 설치 (helm 설치 필수)
  • repository에 다음의 경로로 configuration 파일을 생성한다. kubernetes를 연결해줄 agent 이름의 폴더 아래에 config.yaml을 생성한다.(yml 파일이 아니라 yaml이어야한다)
.gitlab/agents/<agent-name>

config.yaml 작성

gitops:
  manifest_projects:
  - id: [조직명]/[그룹명]/[프로젝트명]
    default_namespace: aiden-vas #eks에서 사용하는 기본 namespace(optional)
  • gitlab에 Kubernetes Cluster 등록
    Project(Repository) > Infrastructure > Kubernetes clsuters로 들어가서 등록
    우측 상단의 Connect Cluster를 누른 후 위에서 작성한 agent-name을 작성하고 create agent를 누른 후 Register를 누르면 생성된다.

    생성한 후 access token과 함께 helm으로 gitlab agent를 설치하는 명령어가 나오는데, 이 명령어를 복사해둔다
  • kubernetes cluster에 gilab agent 설치
    helm이 필수적으로 깔려있어야한다. helm 설치
    위에서 복사한 명령어를 실행하여 gitlab agent 설치 및 연동한다.
    kubectl get po -n gitlab-agent 했을 때 아래와 같이 잘 실행되고 있다면 성공이다.

.gitlab-ci.yml 작성

variables:
  DOCKER_REGISTRY: 000000000000.dkr.ecr.ap-northeast-2.amazonaws.com
  AWS_DEFAULT_REGION: ap-northeast-2
  APP_NAME: [app-name]
  DOCKER_HOST: tcp://docker:2375
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""
  EKS_CONTEXT_PATH: [조직]/[그룹]/[프로젝트명]:[agnet명]
  EKS_DEFAULT_NAMESPACE: aiden-vas
  EKS_DEPLOYMENT_YAML_PATH: [deploy yaml 파일 경로]
cache:
  paths:
    - .m2/repository

stages:
  - package
  - build
  - deploy

package:
  image: adoptopenjdk/maven-openjdk11
  stage: package
  script:
    - 'mvn -B package --file pom.xml'
  artifacts:
    paths:
      - target/*.jar
  only:
    variables:
      - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      

docker_build:
  image: docker:latest
  stage: build
  services:
    - docker:19-dind
  before_script:
    - apk add --no-cache curl jq python3 py3-pip
    - pip install awscli
    - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $DOCKER_REGISTRY

  script:
    - docker build -t $DOCKER_REGISTRY/$APP_NAME:$CI_PIPELINE_IID -t $DOCKER_REGISTRY/$APP_NAME:latest .
    - docker push $DOCKER_REGISTRY/$APP_NAME:$CI_PIPELINE_IID
    - docker push $DOCKER_REGISTRY/$APP_NAME:latest
  only:
    variables:
      - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

deploy:
  image:
    name: bitnami/kubectl:latest
    entrypoint: ['']
  stage: deploy
  script:
    - kubectl config get-contexts
    - kubectl config use-context $EKS_CONTEXT_PATH
    - kubectl get pods -n $EKS_DEFAULT_NAMESPACE
    - kubectl delete -f $EKS_DEPLOYMENT_YAML_PATH
    - kubectl apply -f $EKS_DEPLOYMENT_YAML_PATH
    # - kubectl rollout restart deployment -n $EKS_DEFAULT_NAMESPACE admin-mgmt-deploy
  only:
    variables:
      - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Variables

  • EKS_CONTEXT_PATH: gitlab agent의 config.yaml 파일이 있는 프로젝트 경로
  • EKS_DEFAULT_NAMESPACE: kubernetes cluster에서 사용하는 default namespace (optional)
  • EKS_DEPLOYMENT_YAML_PATH: repository에 deploy에 필요한 yaml 파일을 저장한 경로

deploy

  • image: kubectl 명령어를 쓰기 위해 사용하는 도커 이미지(환경)
  • kubectl config use-context $EKS_CONTEXT_PATH : EKS_CONTEXT_PATH에 있는 config를 가져와서 kubectl 환경 설정
  • kubectl get pods -n [namespace] : pod 리스트 조회. 연결이 잘 되었는지 확인을 위해 작성
  • kubectl delete -f $EKS_DEPLOYMENT_YAML_PATH: pod 삭제. 이미 kubernetes에 pod 가 실행중이기 때문
  • kubectl apply -f $EKS_DEPLOYMENT_YAML_PATH: pod 생성
  • kubectl rollout restart deployment -n $EKS_DEFAULT_NAMESPACE admin-mgmt-deploy: 삭제(delete) & 생성(apply) 방식으로 하는 대신 무중단 방식으로 하고싶다면 이렇게 rollout 명령어를 사용할 수 있다. 이 경우 deploy에 대한 yaml 파일이 필요가 없다.

deploy에 필요한 yaml 파일에 대한 내용은 생략. $DOCKER_REGISTRY/$APP_NAME:latest 이런식으로 최신의 도커 이미지를 가져오도록 pod를 설정해놓으면 yaml 파일 없어도 rollout restart 로 업데이트가 가능하다

실행 확인

이렇게 모든 stage를 완료하면 성공!

profile
DevOps를 살짝 찍먹하는 BackEnd 개발자

0개의 댓글