Docker 기반 CI·CD 파이프라인 구축

CI/CD - GitLab Pipeline 구성 / 파이프라인 문제 발생, 문제 해결 /

wy-family 2024. 12. 6. 10:31

gitlab runner를 구축했었다.

gitlab cicd pipeline을 구성을 해볼 것이다.

pipeline 이라는 건, 컨베이어 벨트 같은것이다. 각각의 스테이지가 있는데

그 스테이지는 컨베이어 벨트로 연결이 되어 있고,

각각 스테이지에서 어떤 결과물들을 다음 스테이지로 컨베이어 벨트를 통해서 넘기는 것.

최종적으로는 완성된 제품이 튀어나오는 것.

GitLab Pipeline도 stages 를 이용해서 관리한다.

stages:

- build

- test

- deploy

 

빌드 스테이지에서는 도커 이미지를 만들고

테스트 스테이지에서는 도커 이미지 기반으로 해서 여러 가지 테스트를 수행하고

테스트가 끝나면 ECR에 push를 하고,

최종적으로 Deploy. 

 

스테이지는 하나 이상의 job 으로 구성된다.

스테이지는 각각의 공정, 단계라고 했다.

그 단계에서 어떤 일을 할지를 알고 있어야 한다.

그거를 바로 job 이라고 한다.

예를 들어 Build Stage의 경우에는

- build를 하기 위한 의존성 설치, 설정 파일 수정, 필요하면 컴파일, Docker build, API 문서화 와 같은 작업들이 이루어지게 된다.

이러한 job 들은 script라고 보면 된다.

예를 들면 이런 식임. yaml 파일임.

stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - echo "Installing dependencies..."
    - echo "Building Docker image..."
    - docker build -t my-app:latest .

test:
  stage: test
  script:
    - echo "Running tests..."
    - docker run my-app:latest pytest tests/

deploy:
  stage: deploy
  script:
    - echo "Pushing to ECR..."
    - docker tag my-app:latest <ECR_URL>/my-app:latest
    - docker push <ECR_URL>/my-app:latest
    - echo "Deploying application..."

실제로 파이프라인을 구성을 해보자!

파이프라인을 구성할 프로젝트를 들어가서 왼쪽 바에 보면, build 라는 곳이 있다.

 

파이프라인을 구성하려고 하는거니까 pipeline editor로 들어가보자.

 

파이프라인을 만들면, 이미 만들어진 코드가 있다.

stages:          # List of stages for jobs, and their order of execution
  - build
  - test
  - deploy

build-job:       # This job runs in the build stage, which runs first.
  stage: build
  script:
    - echo "Compiling the code..."
    - echo "Compile complete."

unit-test-job:   # This job runs in the test stage.
  stage: test    # It only starts when the job in the build stage completes successfully.
  script:
    - echo "Running unit tests... This will take about 60 seconds."
    - sleep 60
    - echo "Code coverage is 90%"

lint-test-job:   # This job also runs in the test stage.
  stage: test    # It can run at the same time as unit-test-job (in parallel).
  script:
    - echo "Linting code... This will take about 10 seconds."
    - sleep 10
    - echo "No lint issues found."

deploy-job:      # This job runs in the deploy stage.
  stage: deploy  # It only runs when *both* jobs in the test stage complete successfully.
  environment: production
  script:
    - echo "Deploying application..."
    - echo "Application successfully deployed."

 

이 코드는 GitLab CI/CD 파이프라인을 정의하는 YAML 형식의 설정 파일입니다. 각 단계의 역할과 동작을 이해하기 위해, 코드를 분석하여 설명하겠습니다.


코드 분석

1. stages 정의

stages:
  - build
  - test
  - deploy
  • stages: Pipeline의 전체 실행 단계를 정의합니다.
  • 각 단계는 순차적으로 실행됩니다. 즉, build → test → deploy 순으로 진행됩니다.
  • 모든 단계는 이전 단계의 성공 여부에 따라 실행됩니다. 만약 하나의 단계가 실패하면 이후 단계는 실행되지 않습니다.

2. build-job

build-job:
  stage: build
  script:
    - echo "Compiling the code..."
    - echo "Compile complete."
  • Job 이름: build-job
  • stage: build에 속하며, Pipeline에서 첫 번째로 실행되는 단계입니다.
  • script:
    • echo "Compiling the code...": 코드 컴파일 작업을 시작하는 메시지 출력.
    • echo "Compile complete.": 컴파일 완료 메시지 출력.
  • 의미: 이 Job은 코드를 컴파일하는 단계로, 모든 작업은 성공해야 이후 단계로 넘어갑니다.

3. unit-test-job

unit-test-job:
  stage: test
  script:
    - echo "Running unit tests... This will take about 60 seconds."
    - sleep 60
    - echo "Code coverage is 90%"
  • Job 이름: unit-test-job
  • stage: test에 속하며, build 단계가 성공한 이후 실행됩니다.
  • script:
    • echo "Running unit tests...": 유닛 테스트 시작 메시지 출력.
    • sleep 60: 테스트 실행 시뮬레이션을 위해 60초 대기.
    • echo "Code coverage is 90%": 테스트 결과 메시지 출력.
  • 의미: 이 Job은 유닛 테스트를 실행하고, 코드 커버리지 상태를 나타냅니다.

4. lint-test-job

lint-test-job:
  stage: test
  script:
    - echo "Linting code... This will take about 10 seconds."
    - sleep 10
    - echo "No lint issues found."
  • Job 이름: lint-test-job
  • stage: test에 속하며, unit-test-job과 병렬로 실행될 수 있습니다.
  • script:
    • echo "Linting code...": 린트 검사 시작 메시지 출력.
    • sleep 10: 린트 검사 시뮬레이션을 위해 10초 대기.
    • echo "No lint issues found.": 린트 결과 메시지 출력.
  • 의미: 이 Job은 린트 검사를 실행하며, 코드 스타일 및 규칙 위반 여부를 확인합니다.

5. deploy-job

deploy-job:
  stage: deploy
  environment: production
  script:
    - echo "Deploying application..."
    - echo "Application successfully deployed."
  • Job 이름: deploy-job
  • stage: deploy에 속하며, test 단계의 모든 Job이 성공해야 실행됩니다.
  • environment:
    • production: 이 Job이 Production 환경으로 배포한다는 것을 명시합니다.
  • script:
    • echo "Deploying application...": 배포 시작 메시지 출력.
    • echo "Application successfully deployed.": 배포 완료 메시지 출력.
  • 의미: 이 Job은 애플리케이션을 실제 운영 환경에 배포합니다.

실행 순서 및 구조 시각화

Pipeline
├── Stage: build
│   └── build-job: Compile the code
├── Stage: test
│   ├── unit-test-job: Run unit tests (60 seconds)
│   └── lint-test-job: Lint the code (10 seconds, runs in parallel with unit-test-job)
└── Stage: deploy
    └── deploy-job: Deploy the application to production
  • 실행 순서:
    1. build-job: 빌드 작업.
    2. unit-test-job & lint-test-job: 테스트 작업(병렬 실행).
    3. deploy-job: 모든 테스트 작업이 성공하면 배포 작업.

주요 특징

  1. 병렬 실행: unit-test-job과 lint-test-job은 동일한 test 스테이지에 속하므로 병렬로 실행될 수 있습니다.
  2. 조건부 실행: deploy-job은 이전 단계의 모든 작업이 성공한 후에만 실행됩니다.
  3. 명확한 환경 설정: deploy-job은 production 환경으로 설정되어 운영 배포 작업임을 명확히 나타냅니다.
  4. 효율성: 각 Job은 필요한 작업만 실행하며, 실패 시 Pipeline을 중단해 불필요한 리소스 낭비를 방지합니다.

이 코드는 기본적인 CI/CD 파이프라인을 구성하는 예제로, GitLab CI/CD의 작동 방식을 잘 보여줍니다.


시각화해서도 보여준다.

실험적으로 다른 job도 추가를 해서 어떻게 보여주는지 확인해보자.

이렇게 추가했더니 에러가 떠서,

여기 stages 에 sec 를 추가해줬더니 해결!


이 게시글, 여기서는 표현할 수가 없지만 방금까지 파이프라인 진행이 안 되고 있었던 문제를 해결하고 있었다.

하...... 몇시간이 흐른건지 모르겠다. 소변도 마렵고, 목도 마르고, 그냥 자리에 앉아서 쭈욱 문제 해결하려고 했다.

휴우...... 초록색 체크 표시가 저렇게 반가울줄이야......

어쨌든, gitlab runner 도 다시, 모든 것들 다 다시....

 

어디서 잘못되었는지 파악하는데에 몇시간이 걸렸다.

파악? 아니지, 왠지 그게 잘못되었던것 같은데,,,, 라는 걸 생각하는데 몇시간이 걸렸다.

그리고 그게 잘못된게 맞는지, 그래서 고치면 해결이 되는게 맞는지를 하려면, 결국 끝까지 다시 해내야 했다.

다행히, 생각했던게 맞았다. 휴우.


휴우......

 

문제의 녀석들은 종료시켜놓고 새롭게 Passed~ 당당히 Passed~~ 아휴 기분좋다


 

파이프라인에서 각각의 job을 눌러보면 어떻게 실행되었는지 확인할 수가 있다.

파이프라인 job script에서 작성했던 echo가 저기에서 실행된걸 볼수가 있다.

그러면 나중에는 직접 build를 할 수 있는 script가 저기에 들어갈 것이다.


test stage에서 unit test가 실패를 했다고 가정을 해보자.

프로그램을 종료할 때, 종료 코드가 0이면 성공이다.

그런데 0이 아닌 다른 값은 실패했다는 걸 의미함.

runner는 이 exit 1 이 되었기 때문에 이 코드, 이 스크립트가 실패했다고 생각하게 되고

그래서 실패를 리턴하게 된다.

 

실패를 하게 되면 그 뒤에 단계들은 그냥 스킵된다.

이제 아기 씻기고 밥먹이고 젖병설거지하고 재우고 다시 공부해야겠다.