[DevOps] 너의 프로그램을 배포 자동화하기 위한 아주 기본적인 지식

Bzeromo·2025년 5월 22일
0

Infra, DevOps, MSA

목록 보기
28/28
post-thumbnail

⚡ DevOps, Github Actions, Jenkins


😓 Jenkins도 여러번 사용했지만 제대로 정리한 적은 없으니...

📌 DevOps

개발과 운영 간의 협업을 강조하는 문화, 움직임, 실천 방법론

  • 소프트웨어 개발 수명주기 전체에 걸쳐 개발자와
    운영자가 지속적으로 소통하고 협력하는 것을 중시

  • 소프트웨어 개발자, 시스템 운영자, 품질 보증(QA) 팀 등
    다양한 IT 부서 간의 협업과 통합 강조

  • 애플리케이션 개발 및 배포 과정을 자동화하고 가속화하는 것이 목표

🛠 주요 원칙

자동화 (Automation)

  • 가능한 모든 것을 자동화하는 것을 강조

  • 이를 통해 빠른 반복과 오류 감소를 이끌어 냄

  • CI/CD 파이프라인 구축, 인프라 자동화, 테스트 자동화 등이 그 예시

코드 관리 (Code Management)

  • 코드와 인프라 설정 등 모든 것을 버전 관리하여 변경 사항을 추적하고 관리

  • 이를 통해 변경 사항의 추적, 롤백, 협업 용이

지속적 통합 (Continuous Integration)

  • 개발자들의 코드 변경이 자동으로 통합되고 테스트되며 빌드되는 프로세스

  • 이를 통해 팀 내에서의 협업을 강화하고 품질을 유지 가능

지속적 제공/배포 (Continuous Delivery/Deployment)

  • 변경 사항이 테스트를 통과하면 자동으로 프로덕션 환경에 배포되는 프로세스

  • 이를 통해 신속하고 안정적인 소프트웨어 배포가 가능

모니터링과 피드백 (Monitoring and Feedback)

  • 실시간으로 시스템 및 애플리케이션의 상태를 모니터링하고

  • 사용자 피드백을 수집하여 지속적으로 개선

  • 이를 통해 서비스 품질을 높이고 문제를 빠르게 해결할 수 있음

🛠 DevOps 주요 실천방법

애자일 개발 방법론과 린(Lean) 원칙 실천

지속적 통합(CI), 지속적 배포(CD), 지속적 모니터링

IaC: 코드로 인프라 정의 및 프로비저닝

마이크로서비스 아키텍처 및 컨테이너 기술 활용

🛠 CI/CD

애플리케이션 개발 및 배포 프로세스를 자동화하고 효율성을 높이는 방법론

CI (Continuous Integration – 지속적 통합)

  • 개발자들이 코드를 공유 레포지토리에 푸시할 때마다
    자동으로 테스트와 빌드가 실행되는 개발 프로세스

  • 이는 팀 내에서의 협업을 촉진하고 통합 오류를 조기에 발견하여
    해결할 수 있는 기회 제공

  • 자동화된 빌드와 테스트, 빠른 피드백, 통합 오류 감소

CD (Continuous Deployment / Continuous Delivery)

  • CI를 확장하여 릴리스 프로세스를 자동화하는 것을 의미

  • Continuous Deployment (지속적 배포)

    • 변경 사항이 테스트를 통과하면 자동으로 프로덕션 환경에 배포

    • 이는 빠른 소프트웨어 배포를 가능하게 하며, 사용자에게 더 빠르게 새로운 기능을 제공할 수 있음

  • Continuous Delivery (지속적 제공)

    • 변경 사항이 테스트를 통과하면 수동으로 프로덕션 환경에 배포할 수 있도록 하는 것

    • 이는 지속적 배포와 유사하지만, 프로덕션 배포의 자동화 단계가 없음

🛠 DevOps 주요 도구

⛓ CI/CD: Jenkins, GitLab CI/CD, Travis CI, CircleCI

⛓ 컨테이너: Docker, Kubernetes

⛓ IaC: Terraform, Ansible, Puppet, Chef

⛓ 모니터링: Prometheus, Grafana, ELK 스택 등


📌 GitHub Actions

주인장의 실습코드가 담긴 관련 repo 참고

GitHub에서 제공하는 CI/CD 자동화 도구

  • 코드 변경 시 자동으로 빌드, 테스트, 배포 등의 작업을 실행할 수 있게 도와주는 기능
  • GitHub 저장소와 완전히 통합되어 있으며, 별도의 서버나 설치 없이 사용 가능

🛠 주요 특징

자동화된 빌드/테스트/배포
→ 코드 푸시 또는 PR 시 자동으로 워크플로우 실행 가능

이벤트 기반 트리거
→ push, pull_request, issue, schedule 등 다양한 GitHub 이벤트에 반응

비밀 관리
→ Secrets 기능을 통해 API 키, 인증 토큰 등 민감한 정보 안전하게 저장 가능

다양한 환경 지원
→ Linux, Windows, macOS 런타임에서 실행 가능

확장성
→ 수천 개의 커뮤니티 액션을 조합하여 고급 기능 구현 가능 (예: 캐싱, 매트릭스 빌드, Slack 알림 등)

쉬운 설정
.github/workflows/*.yml 파일만 작성하면 자동화 파이프라인 즉시 실행 가능

🛠 작동원리

  1. 특정 이벤트 (push, PR, 스케줄 등)가 깃허브 저장소에서 발생

  2. 깃허브 액션은 워크플로 파일 전용 디렉토리 (.github/workflows)를 검색

  3. 해당 이벤트에 대응하도록 만들어진 워크플로 파일을 찾음

  4. 대응하는 파일이 존재하는 경우, 하나 이상의 잡(job) 으로 구성된 워크플로를 실행

  5. 여러 단계의 스텝(step) 으로 구성된 작업은 필요에 따라 러너에서 실행

구성요소 설명

구성요소설명
이벤트(Event)워크플로우를 트리거하는 조건 (예: push, pull_request, issue, schedule 등)
워크플로우(Workflow)자동화 프로세스의 정의 단위. 하나 이상의 작업(Job)으로 구성되며, YAML 파일로 저장됨
작업(Job)워크플로우 내에서 실행되는 개별 작업 단위. 여러 단계(Step)로 구성되며, 병렬 또는 순차 실행 가능
단계(Step)작업(Job) 내에서 실행되는 개별 명령어 또는 액션. 순차적으로 실행됨
액션(Action)단계(Step)에서 실행되는 재사용 가능한 코드 블록. 마켓플레이스에서 가져오거나 직접 작성 가능
러너(Runner)작업(Job)을 실제로 실행하는 환경(가상머신 또는 컨테이너). GitHub 제공 러너 또는 자체 호스팅 러너 사용 가능

워크플로 트리거 (Workflow Trigger)

  • 워크플로를 자동으로 시작하게 만드는 조건 또는 이벤트

  • GitHub 저장소에서 발생하는 다양한 이벤트에 반응 가능

  • 대표적인 트리거 종류

    • push : 브랜치에 코드가 푸시되었을 때
    • pull_request : PR이 생성되거나 수정되었을 때
    • schedule : cron 표현식을 사용한 정기 실행
    • workflow_dispatch : 수동으로 실행 (버튼 클릭)
    • issue, release, deployment, fork, watch 등 기타 GitHub 이벤트

잡 (Job)

  • GitHub Actions 워크플로 내에서 하나의 독립된 작업 집합
  • 각 잡은 여러 단계(steps)로 이루어져 있음
    • 즉, 잡 = 여러 개의 스텝(명령어 또는 액션) 묶음
  • 잡마다 별도의 러너(runner) 환경에서 실행됨
  • 여러 잡을 동시에(병렬로) 실행하거나, 순서·의존성(needs) 지정 가능
  • 정의 위치는 워크플로 YAML의 jobs 키워드

🛠 사용해보기

💡 Github Actions runner

VSCode에 github actions 확장기능 설치

  • github 저장소 복제하기
  • .github/workflows의 yaml 파일 편집, 확인, 실행, 검증

🖥 .github/workflows/01helloWorld.yaml

name: Hello, Bzeromo?

on: 
  workflow_dispatch

jobs:
  hello-world:
    runs-on: ubuntu-22.04
    steps:
        - name: print hello message
          run: echo "Hello, Github Actions!"

🖥 Push 이후

🖥 Run workflow


🖥 02build_gradle.yaml (빌드하고 테스트 하기)

name: 마사이 마라 공원 gradle build

on:
  workflow_dispatch

jobs:
  gradle_build:
    runs-on: ubuntu-22.04
    steps:
        - name: Checkout Code
          uses: actions/checkout@v4

        - name: Setup JDK 17
          uses: actions/setup-java@v4
          with:
            java-version: '17'
            distribution: 'temurin'
        
        - name: Setup Gradle
          uses: gradle/actions/setup-gradle@v4

        - name: Grant execute permission
          run: chmod +x gradlew

        - name: build with gradle
          run: ./gradlew clean build 

        - name: list build/libs directory
          run: ls -al ./build/libs
        
        - name: run springboot application
          run: |
            java -jar ./build/libs/massai_mara_park-0.0.1-SNAPSHOT.jar &
            sleep 30
        
        - name: run automated test #1
          run: |
            curl http://localhost:8080 || exit 1

        - name: run automated test #2
          run: |
            curl http://localhost:8080/images || exit 1

        - name: run automated test #3
          run: |
            curl http://localhost:8080/animal || exit 1

테스트 결과 잘 접속했음을 확인하였다.
(테스트는 한번에 그치고 이후 웹 접속은 불가능하다.)


🖥 03dockerfile_build.yaml (빌드하고 테스트 하기)

name: 마사이 마라 공원 dockerfile build

on:
  workflow_dispatch

jobs:
  dockerfile_build:
    runs-on: ubuntu-22.04
    steps:
        - name: Checkout Code
          uses: actions/checkout@v4

        - name: Setup docker buildx
          uses: docker/setup-buildx-action@v3
        
        - name: Build Docker image
          uses: docker/build-push-action@v5
          with:
            context: .
            file: ./Dockerfile
            push: false
            load: true
            tags: massai_mara:v1
            cache-from: type=gha
            cache-to: type=gha,mode=max

        - name: run docker container
          run: |
            docker run -d --name maratang -p 8080:8080 massai_mara:v1
            sleep 20
            docker ps
            docker logs maratang

        - name: run automated test #1
          run: |
            curl http://localhost:8080 || exit 1

        - name: run automated test #2
          run: |
            curl http://localhost:8080/images || exit 1

        - name: run automated test #3
          run: |
            curl http://localhost:8080/animal || exit 1

테스트 결과 잘 접속했음을 확인하였다.
(테스트는 한번에 그치고 이후 컨테이너 접근은 불가능하다.)


🖥 04compose_build.yaml (빌드하고 테스트 하기)

name: 마사이 마라 공원 compose build

on:
  workflow_dispatch

jobs:
  compose_build:
    runs-on: ubuntu-22.04
    steps:
        - name: Checkout Code
          uses: actions/checkout@v4

        - name: check docker compose version
          run: docker compose version

        - name: build with docker compose
          run: docker compose build

        - name: run with docker compose
          run: |
            docker compose up -d
            sleep 30
            docker compose ps
            docker compose logs

        - name: run automated test #1
          run: |
            curl http://localhost:8080 || exit 1

        - name: run automated test #2
          run: |
            curl http://localhost:8080/images || exit 1

        - name: run automated test #3
          run: |
            curl http://localhost:8080/animal || exit 1

        

테스트 결과 잘 접속했음을 확인하였다.
(테스트는 한번에 그치고 이후 컨테이너 접근은 불가능하다.)


🖥 05dockerhub.yaml (도커 허브에 이미지 올리기)

name: 마사이 마라 공원 dockerhub

on:
  workflow_dispatch

jobs:
  dockerhub:
    runs-on: ubuntu-22.04
    steps:
        - name: Checkout Code
          uses: actions/checkout@v4

        - name: login to docker hub
          uses: docker/login-action@v3
          with:
            username: ${{ secrets.DOCKER_USERNAME }}
            password: ${{ secrets.DOCKER_PASSWORD }}

        - name: docker operations
          run: |
            docker build -t ${{ secrets.DOCKER_USERNAME }}/massai_mara:v1 .
            docker push ${{ secrets.DOCKER_USERNAME }}/massai_mara:v1

        - name: logout from dockerhub
          if: always()
          run: docker logout

github repository secret에 docker username과 password를 변수로 저장하여 보안을 지킨다.

도커 허브에 이미지가 잘 올라와있음을 확인하였다.


🖥 06multiple_jobs.yaml (아티팩트 활용하여 jobs 구분하기)

name: 마사이 마라 공원 multiple jobs

on:
  workflow_dispatch

jobs:
  build:
    name: build JAR
    runs-on: ubuntu-22.04
    steps:
        - name: Checkout Code
          uses: actions/checkout@v4

        - name: Setup JDK 17
          uses: actions/setup-java@v4
          with:
            java-version: '17'
            distribution: 'temurin'
        
        - name: Setup Gradle
          uses: gradle/actions/setup-gradle@v4

        - name: Grant execute permission
          run: chmod +x gradlew

        - name: build with gradle
          run: ./gradlew clean build 

        - name: list build/libs directory
          run: ls -al ./build/libs
        
        - name: Upload JAR artifact
          uses: actions/upload-artifact@v4
          with:
            name: massai_mara_park-0.0.1-SNAPSHOT.jar 
            path: build/libs/*SNAPSHOT.jar

  deploy:
    name: deploy
    needs: build
    runs-on: ubuntu-22.04
    steps:
        - name: Setup JDK 17
          uses: actions/setup-java@v4
          with:
            java-version: '17'
            distribution: 'temurin'
            
        - name: download JAR artifact
          uses: actions/download-artifact@v4
          with:
            name: massai_mara_park-0.0.1-SNAPSHOT.jar
        
        - name: check downloaded files
          run: ls -al

        - name: run springboot application
          run: |
            java -jar ./massai_mara_park-0.0.1-SNAPSHOT.jar &
            sleep 30 || exit 1
        
  # test:
  #   name: app test
  #   needs: deploy
  #   runs-on: ubuntu-22.04
  #   steps:
        - name: run automated test #1
          run: |
            curl http://localhost:8080 || exit 1

        - name: run automated test #2
          run: |
            curl http://localhost:8080/images || exit 1

        - name: run automated test #3
          run: |
            curl http://localhost:8080/animal || exit 1

💡 새로운 Job에 셋업을 다시 해야 한다거나, 아티팩트로 저장했다가 다시 불러오는 등의 번거로움이 있지만 어쨌든 작업을 분류하여 단계별로 실행할 수 있기 때문에 이러한 방식을 사용한다.


🛠 워크플로 배지

  • 오픈소스 프로젝트에서 빌드/테스트/배포/커버리지 등 자동화 상태를 한눈에 알려주는 작은 이미지
  • 프로젝트 신뢰성, 품질, 관리 상태를 쉽게 확인
  • 주로 프로젝트 README.md (또는 문서 페이지) 상단에 삽입
  • Shields.io: 다양한 서비스와 연동할 수 있는 커스텀 배지 제공

🖥 사용해보기(깃허브 워크플로 화면에서 바로 제작 가능)

Passing 표시가 떴음은 성공을 의미한다.

러너 옵션, 스텝, 액션 옵션 등을 활용해서 응용하는 법도 중요하지만 다음 기회에.... 아주 기본적인 것만 다루겠다는 약속은 지켰다.


📌 Jenkins

오픈 소스 자동화 서버로, 소프트웨어 개발 과정에서 코드 변경 사항을 자동으로 통합(빌드), 테스트, 배포하는 CI/CD(지속적 통합/지속적 배포) 도구

  • 개발자가 코드를 저장소(Git 등)에 푸시하면 젠킨스가 이를 감지해 자동으로 빌드와 테스트를 실행하고, 필요하다면 배포까지 이어짐

  • 이를 통해 반복적이고 오류가 발생하기 쉬운 작업을 자동화하여 개발 생산성과 소프트웨어 품질을 크게 높일 수 있음

역사

  • 2004년 Sun Microsystems의 고스케 카와구치(Kohsuke Kawaguchi)가 "Hudson"이라는 이름으로 프로젝트 시작

  • 2011년 Oracle의 Sun 인수 이후 오픈소스 커뮤니티와의 마찰로
    프로젝트가 분리되어 "Jenkins"로 이름 변경

  • 현재는 전 세계적으로 가장 널리 사용되는 CI/CD 자동화 서버로 자리잡음

💡 잘 비교해보고 자신의 프로젝트에 알맞을 것으로 쓰자.

구분젠킨스 (Jenkins)깃허브 액션 (GitHub Actions)
호스팅 방식자체 호스팅 (서버 직접 구축·운영 필요)SaaS(클라우드) 기본, 자체 호스팅 러너도 지원
설정/학습 난이도복잡, 수동 설정 필요, 러닝커브 높음GitHub과 통합, 설정 간편, 러닝커브 낮음
구성 언어Groovy(파이프라인), XML 등YAML(워크플로우)
확장성강력한 플러그인 생태계, 고도의 커스터마이징 가능GitHub Marketplace의 액션 활용, 커스텀 액션 제작 가능
유지보수서버, 플러그인, 보안 등 직접 관리 필요GitHub에서 인프라 관리, 자동 확장
스케일링수동 확장 (노드 직접 추가)자동 확장 (클라우드 러너), 자체 러너 추가 가능
비용오픈소스 (서버 직접 운영 시 인프라 비용 발생)퍼블릭 저장소 무료, 프라이빗 저장소는 사용량 과금
GitHub 연동플러그인 필요, 일부 GitHub 이벤트 미지원GitHub 이벤트와 완벽 연동, PR/이슈 등 자동화 용이
UI/시각화별도 웹 UI, 커스텀 대시보드 지원GitHub 내 통합 UI, PR/커밋과 연계
병렬 처리직접 설정 필요, 병렬화 유연함기본적으로 job 병렬 실행 지원
보안직접 설정 및 관리 필요GitHub 보안 정책 적용, 비밀 관리 내장
프로젝트 규모대규모·복잡한 프로젝트, 다양한 기술스택에 적합소규모~중규모, GitHub 중심의 프로젝트에 적합

Jenkins의 본격적인 사용 방법은 다음으로...

profile
Hodie mihi, Cras tibi

0개의 댓글