Ian's Archive 🏃🏻

thumbnail
AWS환경에서 Jenkins을 활용한 Pipeline구축
CI/CD
2024.03.20.

C 웹서버

c 웹서버 github 레포지토리 주소다.

간단하게 MVC구조로 html파일을 반환하는 웹서버를 구현했다.

main페이지와 404페이지는 간단하게 html파일만 반환하게 구현했는데

상세 페이지 경로로직을

  1. json파일 읽어온다.
  2. 해당 구조체로 변환
  3. 구조체를 view로 넘겨주면 구조체에 맞춰 html 만들어 주기

template engine기능을 전부 넣기는 힘들어 딱 필요한 부분만 만들어 줄 수 있게 만드려 했는데

시간 문제로 인해 .. json만 반환하게 코드를 작성했다.

build는 cMake 활용

AWS EC2 Jenkins 설치

Jenkins서버는 t2.small으로 설치

  1. 필요한 패키지 설치
copyButtonText
$ sudo apt-get update
$ sudo apt-get install \
   ca-certificates \
   curl \
   gnupg \
   lsb-release
  1. Docker의 GPG키 추가

참고로 GPG키는 디지털 서명, 암호화, 소프트웨어 패키지의 무결성 검증에 사용된다

예를 들어, 오픈소스 소프트웨어의 개발자는 GPG키를 사용해 소프트웨어 패키지에 서명하고, 사용자는 이 키를 사용해 다운로드 한 소프트웨어가 원본 그대로 임을 확인한다.

copyButtonText
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  1. 저장소 설정
copyButtonText
echo \
 "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
 $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  1. Docker Engine 설치
copyButtonText
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. Docker의 기본 이미지인 Hello-world 이미지를 통해 정상적으로 설치되었는지 테스트
copyButtonText
sudo docker run hello-world
  1. docker-compose설치
copyButtonText
sudo apt install docker-compose
  1. vi docker-compose.yml 설정파일 생성
copyButtonText
version: '3'
services:
  jenkins:
    image: jenkins/jenkins:lts
    user: root
    volumes:
      - ./jenkins:/var/jenkins_home
    ports:
      - 9000:8080
  1. 컨테이너 실행
copyButtonText
sudo docker-compose up -d
  1. 실행 확인
copyButtonText
sudo docker-compose ps

docker compose ps

잘 올라갔따

  1. 패스워드 입력

9000번 포트 aws에서 열어주고 접근하면 아래 창이 뜨는걸 확인할 수 있다.

first

패스워드는 아래 명령어로 확인

sudo docker exec -it ubuntu_jenkins_1 /bin/bash
cat /var/jenkins_home/secrets/initialAdminPassword

명령어를 입력하면 plugin이 설치된다.

pluginInstall

추가로 cmake설치

jenkins 관리 -> plugin -> installed plugins

그 후에 원하는 version 설치하고 name지정

cmakeAdd

CI/CD

자 간략하게 CICD의 정의 부터 확인하고 가자

CI(Continuous Integration)와 CD(Continuous Deployment 또는 Continuous Delivery)는 모두 소프트웨어 개발 프로세스에서 사용되는 개념이지만, 서로 다른 목표와 방법을 가지고 있다.

Continuous Integration (CI)

CI는 개발자들이 작업한 코드를 주기적으로 빌드하고 테스트하여 공유 저장소에 통합하는 프로세스를 의미

CI의 목표는 팀 내에서 개발자들이 작업한 코드가 지속적으로 통합되고, 버그를 빨리 발견하여 수정함으로써 소프트웨어 품질을 유지하고 개발 프로세스를 가속화하는 것입니다.

  • CI 시스템은 코드 변경 사항이 발생할 때마다 자동으로 빌드 및 테스트를 수행하여 결과를 피드백으로 제공

Continuous Deployment (CD) 또는 Continuous Delivery

CD는 CI의 확장으로, CI를 통해 통합된 코드 변경 사항이 자동으로 프로덕션 환경으로 배포되는 프로세스를 의미

Continuous Deployment는 모든 코드 변경 사항이 자동으로 프로덕션 환경에 배포되는 것을 의미 Continuous Delivery는 프로덕션 환경으로의 배포를 수동으로 결정할 수 있는 옵션을 제공하는 것을 의미

개발자 또는 관리자가 배포를 승인하면 CI/CD 파이프라인은 자동으로 해당 배포를 수행


요약하자면, CI는 코드 변경 사항을 통합하고 테스트하는 프로세스이며, CD는 CI의 결과물을 프로덕션 환경으로 자동으로 또는 수동으로 배포하는 프로세스

CI 구현

  1. 아이템 생성

jenkins접속 후 아이템 생성해 pipeline을 선택 후 아이템 생성

  1. 스크립트 작성

스크립트 작성은 2가지 방법으로 가능

  • 젠킨스 웹 내에서 스크립트 작성, 관리 -> Pipeline Script(default)
  • 프로젝트 내 Jenkinsfile에 스크립트를 작성, 관리 -> Pipeline Script from SCM

1번 사용

  1. 스크립트 작성

Pipeline Script는 2가지 타입으로 작성한다

  • Declarative Pipeline : 쉽게 작성이 가능 (최상단에 pipeline으로 시작)
  • Scripted Pipeline : Declarative 보다 효과적이고 많은 기능으로 포함해서 작성 가능 (but 난이도가 있다. 최상단에 node 지시어로 시작)

모두 Groovy문법 기반이다.

작성한 스크립트

git clone -> mkdir build -> cWebServer/build 이동 -> cmake .. -> make

조금 시행착오가 많았는데 아래가 작성한 script

copyButtonText
pipeline {
    agent any
    stages {
        stage('Install Tools') {
            steps {
                sh 'apt update && apt install -y cmake make' // 필요한 도구 설치
            }
        }
        stage('Clone') {
            steps {
                git branch: 'main', url: 'https://github.com/hohshho/cWebServer.git'
            }
        }
        stage('Build') {
            steps {
                dir('cWebServer') {
                    sh 'mkdir -p build'
                    sh 'cd build'
                    sh 'cmake ..'
                    sh 'make'
                }
            }
        }
    }
}

ciSuccess


Jenkins작업은 완료했고 github에 푸시가 일어날 때 마다 build가 수행되야 하니 Github 설정

  1. Github Token 생성

githubTokenNew

  1. 젠킨스 관리 - Github Token ->credential등록

  2. Github Repository Webhook생성

repository setting - webhooks - Add webhook으로 들어가서

  • Payload URL에 젠킨스주소에 /github-webhook/ 를 추가해서 입력
  • Content type application/json를 선택
  • Add webhook 버튼 클릭

webhook

웹훅이 정상적으로 푸시되는 걸 볼 수 있다.

그리고 jenkins에서 git push를 트리거 할 수 있도록 script를 추가한다

pipeline {
    agent any
    environment {
        TARGET_HOST = "ubuntu@3.35.137.247"
    }
    stages {
        stage('Install Tools') {
            steps {
                sh 'apt update && apt install -y cmake make' // 필요한 도구 설치
            }
        }
        stage('Clone') {
            steps {
                git branch: 'main',
                url: 'https://github.com/hohshho/cWebServer.git',
                credentialsId: 'github_access_token'
            }
        }
        stage('Build') {
            steps {
                dir('build') {
                    sh 'cmake ..'
                    sh 'make'
                }
            }
        }
    }
    triggers {
        githubPush()
    }
}

alt text

요렇게 build로직 완성

CD 구현

본격적으로 시작하기 앞서 Github credential과 aws credential을 등록한다

  1. 젠킨스 관리 - credentials - aws key를 등록

keySave

  1. jenkins관리 - plugins - ssh agent 설치

  2. item 생성

  • 젠킨스에서 하나의 CI/CD 프로젝트를 구축하기 위한 아이템(Item)을 생성
  • FreeStyle / Pipeline 중 Pipeline으로 생성

각각의 방법 장단점을 잠깐 살펴보면

freestyle

장점

  • 웹 기반의 GUI를 통해 여러 플러그인을 쉽게 사용 가능

단점

  • CI 파이프라인에 변경 사항을 만들기 위해서는 젠킨스에 로그인해 각각의 프리스타일 잡의 설정 변경 필요
  • CI/CD의 과정을 콘솔을 통해서만 확인 가능
  • 각각의 과정들을 한번에 보기 어려움

pipeline

  • 코드로 프로젝트 설정을 할 수 있어 젠킨스 웹에 직접 접근하지 않아도 설정 변경 가능
  • 웹을 통한 설정도 가능
  • CI/CD 파이프라인 설정을 하나의 스크립트 파일(Jenkinsfile)로 프로그래밍을 통해 제어
    • 일반 코드처럼 버전 관리가 가능하게 된다.
  • GUI를 통해 과정 확인 가능
  1. 스크립트 수정
copyButtonText
pipeline {
    agent any
    environment {
        TARGET_HOST = "ubuntu@xxx.xxx.xxx.xxx"
    }
    stages {
        stage('Install Tools') {
            steps {
                sh 'apt update && apt install -y cmake make' // 필요한 도구 설치
            }
        }
        stage('Clone') {
            steps {
                git branch: 'main',
                url: 'https://github.com/hohshho/cWebServer.git',
                credentialsId: 'github_access_token'
            }
        }
        stage('Build') {
            steps {
                dir('build') {
                    sh 'cmake ..'
                    sh 'make'
                }
            }
        }
        stage('Deploy') {
            steps {
                sshagent(credentials: ['aws_key']) {
                    sh '''
                    ssh -o StrictHostKeyChecking=no ${TARGET_HOST} "
                        cd github/cWebServer &&
                        git pull &&
                        cd ../.. &&
                        ./deploy.sh
                    "
                    '''
                }
            }
        }
    }
    triggers {
        githubPush()
    }
}

deploy

정상적으로 확인 가능하다

deploy

배포 대상이 되는 서버에 deploy.sh가 위치한다.

copyButtonText
#!/bin/bash

# 1. 8092 포트가 열려있는지 확인하고 프로세스 ID 가져오기
PID=$(lsof -ti :8092)

# 2. 포트가 열려있는 경우 프로세스를 종료
if [ ! -z "$PID" ]; then
    kill -15 $PID
fi

# 3. cWebServer 실행(프로세스가 터미널 세션 끊어도 계속 실행)
cd github/cWebServer/build
make
chmod +x cWebServer
nohup ./cWebServer -d >> application.log 2>&1 &

처음엔 실행 파일만 운영 서버에 전송하고 싶었다. 하지만 빌드 된 파일을 전송하면 경로문제 때문에 코드를 제대로 읽어오지 못함 ㅜ

c와 빌드 툴에 대한 이해가 부족했기 때문에 다른 방법을 고민 하다가

젠킨스 서버에 있는 코드를 전부 밀어줘서 배포 서버에서 다시 빌드하자라고 생각하고 스크립트를 작성 후 테스트를 진행

… deploy과정에서 nohup옵션을 주고 백그라운드 실행을 했는데 세션이 종료되지 않고 계속 물고있었다. (실행은 되는데 파이프라인 종료를 안함 ㅋㅋ)
(nohup옵션은 세션과 연결 종료해도 프로세스 계속 실행)

일단 배포가 수행 되는게 목표니 다른 방법을 고민했고

운영 서버에서 git pull을 받고, 빌드를 다시해서 실행파일 생성 후 서버 다시 실행

으로 로직을 수정했다.

이렇게 해도 될까? 라는 고민을 했는데

젠킨스 서버에서 ci과정을 통해 빌드 ok = git main브랜치 이상 없다 = deploy ok상태

라 생각해서 이방식으로 구현

이렇게 구현하면 단점이 git을 운영서버에서 clone해 빌드를 수행하기 때문에

  1. 용량을 많이 차지
  2. 쓸데없이 빌드를 한번 더함

-> 컴퓨팅 자원 낭비

그래도 돌아는 가니까 … 일단 이렇게 마무리 지었다.

Thank You for Visiting My Blog, I hope you have an amazing day 😆
© 2023 Ian, Powered By Gatsby.