DevOps & Pipeline

DevOps

image

  • DevOps = Development(개발) + Operations(운영)
  • 개발과 운영의 거리를 줄인다.
  • 데브옵스는 애플리케이션과 서비스를 빠른 속도로 제공하기 위한 문화, 철학, 방식, 도구를 모두 포함한다.
  • 데브옵스는 컨테이너, CI/CD, 자동화, MSA, IaC 등의 개념과 연관이 있다.
  • 컨테이너는 개발자 간의 개발 환경과 배포환경과의 차이를 줄여 빠르고 안정적인 배포가 가능해진다.

CI/CD 파이프라인

image

  • 파이프라인은 소스코드부터 배포 환경 관리까지의 모든 프로세스를 자동화하는 것을 의미한다.
  • CD (Continuous Integration)
    • 지속적 통합
    • 배포가능한 아티팩트(Jar/Image)를 빌드하는 단계
    • 소스코드를 배포 가능한 아티팩트로 만드는 것을 자동화한다.
  • CD (Continuous Delivery/Deployment)
    • 지속적 배포
    • 실제 환경에 아티팩트를 배포하는 단계
    • 아티팩트를 배포 환경에 배포
  • 이렇게 CD/CD 파이프라인을 구성해서 빌드 및 배포 단계를 자동화하여 운영작업을 편리하게 할 수 있다.

Github Actions

  • Github에 소스코드를 push하면 Github Actions에서 CI/CD 파이프라인을 자동으로 실행시킬 수 있다.
  • Github Actions을 사용하여 개발자의 PC나 별도의 빌드용 서버가 없이 파이프라인을 실행할 수 있다.
  • 프로젝트 폴더 안의 .github/workflows 폴더 안에 yml파일을 구성하여 파이프라인을 실행한다.

image

  • 실제 진행중인 프로젝트의 workflows폴더 안의 yml 파일이다.
  • Github가 이 파일을 자동으로 인식하여 파이프라인을 실행한다.

image

  • Github에서 일정 크기의 러너 서버를 무료로 지원해준다.
  • 사용자는 러버 서버를 빌려 이 서버 위에서 Github Actions을 통해 워크플로우를 자동으로 실행할 수 있다.
  • Github Actions에 문법에 맞게 코드를 작성하면 자동으로 코드를 읽어들여 워크 플로우가 실행된다.

Github Actions 문법

image

  • name:에 워크 플로우의 이름을 지정한다.
  • on:아래에 트리거를 설정한다.
  • jobs:아래에 여러 작업으로 나누어진 워크플로우를 작성한다. build-and-push로 설정하여 job을 여러개 지정할 수 있다.
  • runs-on:에 작업이 실제로 실행될 러너(서버)를 지정한다.
  • steps:는 각 작업을 나타내고, 여러개 지정할 수 있다.

image

  • 시간 트리거 : 특정 시간을 설정하면 해당 시간에 워크플로우가 자동으로 실행된다.
  • 푸시 트리거 : 소스코드를 변경하고 Github에 push하면 자동으로 워크 플로우를 실행한다.

image

  • 모든 작업(steps)는 러너에서 실행된다.
  • steps:아래의 uses:에 actions/checkout@v2을 사용하면 Github의 소스코드를 러너에 다운받을 수 있다.

image

  • 도커의 buildx 기능을 활성화하면 멀티플랫폼 빌드나 캐싱과 같은 기능을 사용할 수 있다.
  • steps:아래의 uses:에 docker/setup-buildx-action@v1을 사용하면 buildx 기능을 사용하여 도커의 기능을 확장한다.

image

  • 도커에 로그인해야지만 이미지를 푸시할 수 있다. 따라서, 도커 로그인 정보를 입력해주어야한다.
  • steps:아래의 uses:에 docker/login-action@v1을 사용하면 도커 로그인 명령을 실행한다.
  • with:아래에 도커의 로그인 정보를 입력한다.

image

  • Github의 시크릿 기능을 활용하여 시크릿에 입력되어 있는 로그인 정보를 가져와 사용한다.

image

  • build-push-action은 소스코드를 사용해서 이미지를 빌드하고 이미지를 레지스트리에 푸시하는 액션이다.
  • with:아래에 build-push-action에 필요한 정보를 입력한다.

Github Actions 실제 활용

name: CICD

on:
  pull_request:
    branches: [ "develop" ]
    types: [ closed ]

jobs:
  build-and-upload:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@v4
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Make application.yml
        working-directory: ./backend
        run: |
          cd ./src/main
          mkdir resources
          cd ./resources
          touch ./application.yml
          echo "$" > ./application.yml
        shell: bash

      - name: Grant execution permission for gradle
        working-directory: ./backend
        run: chmod +x gradlew

      - name: Build with Gradle Without test
        working-directory: ./backend
        run: ./gradlew clean build -x test

      - name: Docker build & push
        working-directory: ./backend
        run: |
          docker login -u $ -p $
          docker build -t $/moyeobwa -f Dockerfile .
          docker push $/moyeobwa

      - name: Deploy
        uses: appleboy/ssh-action@master
        with:
          host: $
          username: ubuntu
          key: $
          port: $
          script: |
            docker stop moyeobwa
            docker rm moyeobwa
            docker image rm -f moyeobwa
            docker pull $/moyeobwa
            docker run -d -p 8080:8080 --name moyeobwa $/moyeobwa
  • 위 yml파일은 실제 프로젝트에 사용한 워크플로우 이다.
  • pull request가 develop 브랜치에서 닫힐 때 워크플로우가 실행된다.
  • 워크플로우 단계 구성
    1. Set up JDK 17: Java 개발환경을 설정한다. JDK 17을 사용하고 Temurin 배포를 설치한다.
    2. Make application.yml: 어플리케이션의 설정 파일인 application.yml을 생성하고 시크릿으로부터 값을 이 파일에 저장한다. ./backend 폴더에서 run아래 명령어가 실행된다.
    3. Grant execution permission for gradle: Gradle 실행 권한을 부여한다.
    4. Build with Gradle Without test: Gradle을 사용하여 테스트를 제외하고 빌드한다.
    5. Docker build & push: Docker 이미지를 빌드하고 Docker 레지스트리에 푸시한다. run 아래에 시크릿에서 받아온 도커 로그인 정보를 입력하고, 해당 레지스트리에 도커파일을 사용하여 이미지를 빌드하고 푸시한다.
    6. Deploy: SSH를 사용하여 호스트 서버로 접속하여 이전 버전의 컨테이너를 정지하고 삭제한 후, 새로운 Docker 이미지를 풀(pull)하여 컨테이너를 다시 실행한다. with아래에 EC2 서버 주소, 포트 등의 정보를 시크릿에서 받아와 접속하고, script에 입력된 명령어를 통해 EC2서버에 실행되어 있는 이전 컨테이너를 정지 및 삭제하고, 새롭게 생성한 이미지를 풀하여 다시 실행한다.