[gitlab runner][aws] 깃랩 파게이트 자동배포 cicd

해질녘·2022년 7월 28일
1

DevOps

목록 보기
2/6
post-thumbnail
이 글은 이번 파이프라인이야말로 성공이 뜨도록 기도하며 쓰고 있다... 

이 수준이라 3개월 뒤에 이걸 수정할 일이 생기면 기억 안 날 거 같아서 써둠

보안 그런거 없음 주의 ;;

그냥 쭉 내려서 내가 참고한 문서 목록만 보는게 더 이득일듯...

gitlab runner

깃랩에서는 CI/CD를 자동으로 해준다. 그러기 위해서는 그 작업이 돌아가는 머신이 있어야 할텐데, 보통은 ec2에 gitlab runner를 깔아두고 등록해서 쓰는 모양이다. 소마에서 이미 디폴트로 등록해준 머신이 있었다.

할 일 하나 줄어서 좋은 건 줄 알았는데 머신 직접 연결해서 디버깅 못 하는 게 참 답답했다... 한번 빌드해서 오류 메시지 보는게 3분 걸림 ㅠㅠ 그리고 3분이면 이미 집중력 안드로메다로 날아갈 시간...

깃랩 러너가 작업을 돌리는 환경이 여러 종류가 있는데 이 중에서 내가 사용한 것은 docker cli이다.

파게이트

파게이트 세팅은 이 전에 했으니까 패스...

이 글에서 다루지 않는 것

  • aws에 ecr 리포지토리 생성 + 푸시
  • aws에서 파게이트 시작해서 Hello, world 띄우기

이미 한번 해 뒀고 그걸 update한다는 전제 하에 작성되었다.

이 글에서 쓰는 것

  • spring boot with gradle
  • docker
  • gitlab runner
  • aws ecr
  • aws fargate

야믈

일단 첫부분

    image: docker:20.10
    variables:
      DOCKER_REGISTRY: xxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com
      APP_NAME: xxxxx
    stages:
      - build
      - test
      - package
      - deploy
  • build

    • gradle로 스프링부트 프로젝트 빌드 -> xxx.jar
  • test

    • 일단 패스
  • package

    • docker로 jar 파일 빌드하고 ecr에 업로드
  • deploy

    • ecr 리포지토리로부터 현재 작동중인 파게이트 서비스 업데이트

build

    build:
      image: gradle:alpine
      stage: build
      script:
        - echo "gradle build"
        - chmod +x gradlew
        - ./gradlew clean
        - ./gradlew build
      artifacts:
        paths:
          - build/libs/*.jar
        expire_in: 1 day
      only:
        - master
  • image

    • 빌드를 위해 gradle을 이용한다.

    • alpine은 경량 버전이라는 뜻이다.

    • 버전에 대한 언급이 없으니 latest 버전을 가져오게 된다.

  • script

    • gradlew 파일에 권한 설정 안 주면 진행 불가.
    • clean, build
  • artifacts

    • 빌드한 결과물이 다음 stage로 넘어갈 때에도 저장이 되어 있어야 한다. 그래서 스테이지 넘길 때도 저장이 되도록 지정해준다.
    • expire_in 하루동안 저장
  • only

    • 마스터 브랜치의 변경에만 적용

test

  test:
  image: gradle:alpine
  stage: test
  script:
    - chmod +x gradlew
    - ./gradlew test
  only:
    - master

(09-16 수정)

  • gradle 이용하여 test 실행한다.

package

패키지의 슬픈 썰: 원래 도커 image 빌드랑, 빌드한 이미지 ecr에 업로드 하는 단계를 2개로 쪼개려고 했는데

그렇게 하면 단계가 넘어가서 파일을 어떻게 넘겨줘야될지... 인터넷으로 찾아본 바 이런 방법을 쓴다

  • 빌드 단계에서 dockerHub에 올렸다가 ecr에 올리는 단계에서 dockerHub에서 내려받기

private 하지 않기 때문에 이 방법을 쓰고 싶지 않았다

package:
  stage: package
  image:
    name: docker:stable
  services:
    - name: docker:dind
      alias: dockerdaemon
  variables:
    # Tell docker CLI how to talk to Docker daemon.
    DOCKER_HOST: tcp://dockerdaemon:2375/
    # Use the overlayfs driver for improved performance.
    DOCKER_DRIVER: overlay2
    # Disable TLS since we're running inside local network.
    DOCKER_TLS_CERTDIR: ""
  script:
    # GitLab has a built-in Docker image registry, whose
    # parameters are set automatically. You can use some
    # other Docker registry though by changing the login and
    # image name.
    - docker build -t xxxxx:latest .
    # now upload to ecr
    - ntpd -q -p time.nist.gov
    - apk add --no-cache curl jq python3 py-pip
    - pip install awscli
    - aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
    - aws --version
    - docker info
    - docker --version
    - docker tag xxxxx:latest $DOCKER_REGISTRY/$APP_NAME:latest
    - docker push $DOCKER_REGISTRY/$APP_NAME:latest
  only:
    - master
  • image

    • 도커를 받아준다
  • services

    • 도커를 근데... 문제가 있다 docker위에서 이미 cli를 실행 중 인데 어떻게 도커를 쓴단 말인가?

      • 이 문제에 대해 해결책 2가지
        1. 현재 실행되고 있는 docker를 어떻게 잘 이용하기
        2. docker 위에 docker 하나 더 올려서 그쪽을 사용
      • 후자를 DinD = Docker in Docker라고 한다. 그러기 위해서 설정을 해 줘야 한다.
  • script

    • 도커 빌드
    • ecr에 업로드
    • $DOCKER_REGISTRY , $APP_NAME은 제일 위에서 정의해준 변수

deploy

deploy:
  stage: deploy
  image:
    name: docker:stable
  services:
    - name: docker:dind
      alias: dockerdaemon
  variables:
    TASK_DEF_NAME: xxxxx-backend-task
    CLUSTER_NAME: xxxxx-cluster
    SERVICE_NAME: xxxxx-backend-task-service
    DOCKER_HOST: tcp://dockerdaemon:2375/
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
  script:
    - echo "deploy start"
    - ntpd -q -p time.nist.gov
    - apk add --no-cache curl jq python3 py-pip
    - pip install awscli
    - aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
    #- filePath="/bin/LEAP/$TASK_DEF_NAME.json"
    #- export task_version=$(aws ecs describe-task-definition --cli-input-json file://$filePath --region $region | jq --raw-output '.taskDefinition.revision') --debug
    #- aws ecs register-task-definition --cli-input-json $filePath.sjon --region $AWS_REGION --debug
    #- aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --task-definition $TASK_DEF_NAME --region $AWS_REGION 망한시도들 버리지 않고 남겨두기
    - aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --force-new-deployment
  • 도커를 다시 써야 하므로 도커 세팅을 불러와준다

  • script

    • aws cli에 로그인 하고 있다. 친절한 GUI로 뭐든 되는 것처럼 보이던 aws, 막상 보니까 GUI로 해결이 안 됨. 다 구워버려 구이~ (자동화 하려면 어차피 써야됨...)
    • 깃랩 settings-CI/CD-Varibles에서 미리 시크릿또❤️환경변수를 등록해둔다.
  • aws 설정

    • 배포 용도로 새로운 IAM 유저를 만들어줄 것이다. 거기서 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY를 저장해주자.
    • 마지막 권한은 aws 다큐멘테이션에서 json 가져옴.
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "application-autoscaling:Describe*",
              "application-autoscaling:PutScalingPolicy",
              "application-autoscaling:DeleteScalingPolicy",
              "application-autoscaling:RegisterScalableTarget",
              "cloudwatch:DescribeAlarms",
              "cloudwatch:PutMetricAlarm",
              "ecs:List*",
              "ecs:Describe*",
              "ecs:UpdateService",
              "iam:AttachRolePolicy",
              "iam:CreateRole",
              "iam:GetPolicy",
              "iam:GetPolicyVersion",
              "iam:GetRole",
              "iam:ListAttachedRolePolicies",
              "iam:ListRoles",
              "iam:ListGroups",
              "iam:ListUsers"
            ],
            "Resource": [
              "*"
            ]
          }
        ]
      }
  • ecr에서 태스크 정의 및 서비스 업데이트하기

    • 원래는 현재 태스크 정의를 json으로 받은 후 그걸 이용해서 새로운 버전의 task definition으로 넣어주려 했다
    • json 및 리눅스 파일 시스템 등과 친하지 않아서 어렵다...
    • 궁금한 사람은 참고 문서에서 마지막꺼 보셈
    • 그래서 그냥 update-service에서 자동으로 latest 태그 붙은 ecr 이미 가져오도록 갱신만 해주었다.. (이러면 task definition 버전 안 올라감.)

미래의 나를 위한 문제

  • aws cli 1에서 2로 업데이트 필요
  • pipeline 시간 너무 오래 걸림 (4분 45초)
  • 업데이트는 되는데 task definition 버전 안 올라가는거 너무 킹받는다.

참고 문서들

0개의 댓글