Jenkins 를 통한 NGINX 구성 변경 및 배포 자동화 구현

이 블로그 포스트 에서는 Jenkins 를 활용하여 NGINX 서버의 구성 파일을 효율적으로 관리하고, 변경 사항을 자동으로 배포하는 방법을 설명합니다. 이 글은 CI/CD 환경에서 Jenkins의 강력한 기능을 활용하여 NGINX 설정을 동적으로 업데이트하고, 이를 통해 배포 속도와 안정성을 향상시키는 과정을 중점적으로 다룹니다.

목차

1. Jenkins 란?
 1-1. CI/CD 구현 이점
2. Jenkins를 통한 NGINX 웹 서버 배포 자동화
 2-1. GitHub와 Jenkins 연동
 2-2. Jenkins CI/CD 파이프라인 설계
 2-3. NGINX 테스트 및 배포
3. 결론

1. Jenkins 란?

Jenkins는 가장 널리 사용되는 오픈소스 CI/CD 도구로, 소프트웨어 개발 프로세스를 자동화하는 데 핵심적인 역할을 합니다. Jenkins는 소스 코드의 빌드, 테스트, 배포를 자동화하여 개발 및 운영 팀 간의 협업을 강화하고, 반복적인 작업에 소요되는 시간을 대폭 줄여줍니다.

1-1. CI/CD 구현 이점

Jenkins를 활용한 CI/CD는 코드 변경 사항을 지속적으로 통합하고, 자동화된 테스트와 배포를 통해 품질을 보장합니다. 이를 통해 배포 속도가 빨라지고, Human Error 가능성을 줄이며, Downtime 없는 안정적인 무중단 서비스를 제공합니다. 특히 NGINX와 같은 웹 서버를 관리할 때 Jenkins를 활용하면 구성 변경에서 배포까지의 과정을 자동화하여 효율성을 극대화할 수 있습니다.

2. Jenkins를 통한 NGINX 웹 서버 배포 자동화

NGINX는 고성능 웹 서버로, 전 세계적으로 가장 많이 사용되는 서버 소프트웨어 중 하나입니다.

Jenkins와 NGINX를 결합하면 구성 변경을 GitHub와 같은 버전 관리 도구를 통해 관리하고, Jenkins의 CI/CD 기능을 활용하여 자동 배포할 수 있습니다.

2-1. GitHub와 Jenkins 연동

Jenkins와 GitHub를 연동하면 코드 저장소에서 발생하는 변경 사항을 자동으로 감지하여 파이프라인을 실행할 수 있습니다. 이를 위해 GitHub Webhook을 설정하고 Jenkins에서 GitHub 플러그인을 설치하여 동기화 상태를 유지해야 합니다.

연동이 완료되면 NGINX 구성 파일의 변경 사항을 Commit과 Push로 간단히 배포 프로세스를 시작할 수 있습니다.

Jenkins 서버에서 GitHub plugin이 활성화 되어 있어야 합니다.

GitHub plugin이 활성화 되어있지 않다면 Jenkins의 Dashboard > Jenkins 관리 > Plugins 탭의 Available plugins 카테고리에서 Github plugin을 다운로드 할 수 있습니다.

Jenkins 와 연동을 진행할 GitHub Repository의 “Settings” 탭으로 이동합니다.

“Code and automation” 카테고리의 “Webhooks” 탭을 클릭하여 Webhooks을 추가합니다.

Payload URL 입력 필드에 Jenkins 서버의 주소를 입력합니다. 이는 GitHub Webhooks이 접근할 수 있는 Public IP 혹은 인터넷에 노출된 도메인일 수 있습니다.

Webhooks 생성이 정상적으로 완료되면 초록색 체크 표시와 함께 Jenkins에 대한 GitHub Repository Push Webhook이 연동된 것을 확인할 수 있습니다.

2-2. Jenkins CI/CD 파이프라인 설계

Jenkins에서 NGINX 배포를 위한 파이프라인은 다음 단계로 설계할 수 있습니다.

  1. 코드 클론: GitHub에서 최신 NGINX 구성 파일을 가져옵니다.
  2. 테스트 환경 배포: 변경된 설정을 테스트 서버에 배포하여 동작을 확인합니다.
  3. 문법 검사nginx -t 명령을 통해 구성 파일의 문법 오류를 검사합니다.
  4. 실제 서버 배포: 모든 테스트가 성공하면, Jenkins가 실제 NGINX 운영 서버에 변경 사항을 적용하고 서비스를 재시작합니다.

이러한 파이프라인 설계를 통해 자동화된 배포를 실현할 수 있습니다.

위 파이프라인 설계를 기반으로 파이프라인 스크립트를 작성합니다.

NGINX STORE GitHub: Jenkinsfile

pipeline {
    agent any

    environment { // 환경변수 설정
        NGINX_SERVER = '192.168.201.93'
        SSH_PORT = '22'
        SSH_USER = 'root'
        DEPLOY_PATH = '/etc/nginx/conf.d/'
    }

    stages {
        stage('checkout') { // 코드 클론 과정
            steps {
                git branch: 'main', 
                credentialsId: 'git-credential', // GitHub Personal Credentials
                url: 'https://github.com/itian-nginx/jenkins-cicd.git'
            }
        }
        stage('validate') { // 테스트 환경 배포 및 구성 검증 과정
            steps {
                dir('devopskim/nginx-oss/examples/webserver-cicd') { // 작업 디렉토리 변경
                    sh '''
                    # Test NGINX configuration locally
                    docker run -i -d -p 2377:80 --name=test-nginx nginx nginx -g "daemon off;"
                    docker exec test-nginx mkdir /var/log/nginx/access
                    docker exec test-nginx mkdir /var/log/nginx/error
                    docker cp default.conf test-nginx:/etc/nginx/conf.d/default.conf
                    docker exec test-nginx cat /etc/nginx/conf.d/default.conf

                    # Validate configuration
                    docker exec test-nginx nginx -t || (docker rm -f test-nginx && exit 1)

                    # Clean up after validation
                    docker rm -f test-nginx
                    '''
                }
            }
        }
        stage('copy') { // 실제 NGINX 서버에 파일 복사
            steps {
                dir('devopskim/nginx-oss/examples/webserver-cicd') { // 작업 디렉토리 변경
                    sshagent(['itian-nginx1-ssh']) {
                        sh '''
                        scp -P ${SSH_PORT} -o StrictHostKeyChecking=no default.conf ${SSH_USER}@${NGINX_SERVER}:${DEPLOY_PATH}
                        scp -P ${SSH_PORT} -o StrictHostKeyChecking=no change-index.html ${SSH_USER}@${NGINX_SERVER}:/usr/share/nginx/html/
                        '''
                    }
                }
            }
        }
        stage('deploy') { // 실제 NGINX 서버 구성 검증 및 Reload를 통한 구성 변경 사항 반영
            steps {
                sshagent(['itian-nginx1-ssh']) {
                    sh '''
                    ssh -p ${SSH_PORT} -o StrictHostKeyChecking=no ${SSH_USER}@${NGINX_SERVER} "nginx -t"
                    ssh -p ${SSH_PORT} -o StrictHostKeyChecking=no ${SSH_USER}@${NGINX_SERVER} "nginx -s reload"
                    '''
                }
            }
        }
    }

    post {
        success {
            echo 'Deployment successful!'
        }
        failure {
            echo 'Deployment failed!'
        }
    }
}

다음은 파이프라인 스크립트 내 각 Stage에 대한 설명입니다.

  • checkout: 코드 클론
    • GitHub에서 최신 코드를 Jenkins 작업 공간으로 가져옵니다.
  • validate: 테스트 환경 배포 및 문법 검사
    • NGINX 구성 파일의 문법 오류를 확인하고, 로컬 테스트 환경에서 배포 검증을 진행합니다.
  • copy: 파일 복사
    • 검증된 NGINX 구성 파일과 정적 파일을 실제 서버로 복사합니다.
  • deploy: 실제 NGINX 서버에 배포
    • NGINX 서버에 새로운 구성을 적용하고, 서비스를 재시작하여 변경 사항을 반영합니다.

2-3. NGINX 테스트 및 배포

실행 중인 NGINX 서버의 구성과 접속 페이지를 확인합니다.

GitHub 레포지토리에 웹 서버용 NGINX 구성 파일과 HTML 파일을 commit 하고 push 합니다.

default.conf
# 로그 형식 정의
log_format default '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

# 기본 서버 설정
server {
    listen 80 default_server;
    server_name localhost;

    # 액세스 로그 설정
    access_log /var/log/nginx/access/nginx.access.log default;

    # 에러 로그 설정 (디버그 모드)
    error_log /var/log/nginx/error/nginx.error.log debug;

    # 기본 웹 경로 및 인덱스 파일 설정
    location / {
        root /usr/share/nginx/html;
        index change-index.html;
    }

    # 50x 에러 페이지 설정
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}
change-index.html
<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NGINX STORE</title>
    <style>
        .main-section {
            text-align: center;
            margin-bottom: 40px;
        }

        h1 {
            font-size: 3rem;
            font-weight: bold;
            margin-bottom: 20px;
            color: #FFFFFF;
        }

        .highlight {
            background: linear-gradient(90deg, #4380a9 0%, #5bf09e 100%);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }

        p {
            font-size: 1.2rem;
            margin-bottom: 30px;
            color: #CCCCCC;
            max-width: 600px;
            margin-left: auto;
            margin-right: auto;
        }

        .cta-button {
            padding: 12px 24px;
            border: 2px solid #FFFFFF;
            border-radius: 25px;
            background-color: transparent;
            color: #FFFFFF;
            font-size: 1rem;
            cursor: pointer;
            transition: background-color 0.3s ease, color 0.3s ease;
        }

        .cta-button:hover {
            background-color: #FFFFFF;
            color: #0A0A0A;
        }

        #app {
            text-align: center;
            background-color: #0a0a0a;
            color: #fff;
            height: 100vh;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            overflow: hidden
        }
    </style>
</head>

<body style="background-color: #0A0A0A;">
    <div id="app">
        <div class="main-section">
            <h1>Welcome to <span class="highlight">NGINX STORE</span></h1>
            <p>API Gateway, API Security, Cloud-Native, Kubernetes, Service Mesh, MSA, Proxy, Web Server, NGINX 등 다양한
                주제의
                최적의 실무 사례를 알아보세요. 업계 선도 기업들이 사용하는 전략과 방법을 통해 더 나은 성과를 달성하세요.</p>
            <button class="cta-button" onclick="navigateToLink()">Get Started ➜</button>
        </div>
    </div>

    <script>
        function navigateToLink() {
            window.location.href = "https://nginxstore.com";
        }
    </script>
</body>

</html>
$ git add . 

$ git commit -m "NGINX Web Server Deploy With Jenkins"

$ git push

GitHub 레포지토리에서 Push 사항을 확인합니다.

Jenkins 웹 대시보드를 확인하면, 레포지토리에 Push가 일어남과 동시에 파이프라인 스크립트가 이를 인식하여 실행되는 것을 확인할 수 있습니다.

3. 결론

Jenkins를 활용한 NGINX 자동화는 반복적인 수작업을 줄이고, 신속하고 안정적인 배포를 가능하게 합니다. GitHub와의 연동을 통해 NGINX 구성 파일을 버전 관리하며, Jenkins의 CI/CD 파이프라인을 통해 배포 프로세스를 자동화함으로써 서비스 가용성과 품질을 높일 수 있습니다. Jenkins를 통한 NGINX의 배포 자동화는 현대 DevOps 환경에서 필수적인 조합으로, 이를 통해 효율적이고 신뢰할 수 있는 배포 시스템을 구축할 수 있습니다.

Jenkins 를 통한 NGINX 자동화 배포와 같은 다양한 CI/CD 솔루션을 통한 마이크로서비스 아키텍처 구현에 한 발짝 더 다가가고 싶으신가요?

NGINX STORE 블로그의 CI/CD 카테고리를 참고하거나 NGINX STORE에 직접 문의하여 사용 사례에 맞는 CI/CD 솔루션을 상담 받아보세요.