본문 바로가기
AWS/EKS

[AEWS2] 7-1. EKS CI/CD - Jenkins

by okms1017 2024. 4. 21.
728x90

✍ Posted by Immersive Builder  Seong

 

 

1. 사전 준비 

Docker Hub 

DockerHub(https://hub.docker.com/) 사이트에 깃허브 계정(okms1017)으로 가입합니다. 

 

DockerHub

 

Docker 

DockerHub에서 Ubuntu 20.04 이미지를 내려받아 커스터마이징합니다. 

Apache와 Figlet을 설치하고 버전정보와 함께 간단한 웹 페이지를 구성합니다. 

 

# ubuntu image download
$ docker pull ubuntu:20.04
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
ubuntu       20.04     33985b2ba010   8 days ago   72.8MB

# WEB 디렉토리 생성
$ mkdir -p /root/myweb && cd /root/myweb

# Dockerfile 생성 
$ vi Dockerfile 
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=1.0.0 NICK=okms1017
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
    sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
    apt-get update && apt-get install -y apache2 figlet && \
    echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
    echo "<pre>" >> /var/www/html/index.html && \
    figlet AEWS Study >> /var/www/html/index.html && \
    echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]

# Docker image Build
$ docker build -t myweb:v1.0.0 .
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
myweb        v1.0.0    04e2c155fe0c   11 seconds ago   238MB
ubuntu       20.04     33985b2ba010   8 days ago       72.8MB

# Docker image 히스토리
$ docker image history myweb:v1.0.0
$ docker image inspect myweb:v1.0.0

# Container 실행
$ docker run -d -p 80:80 --rm --name myweb myweb:v1.0.0
45c124ad5b5562f7a42f05a6c66642aaf1582a70536ad880574c295b6899a7bf
$ docker container ls
$ docker ps 
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                               NAMES
45c124ad5b55   myweb:v1.0.0   "usr/sbin/apache2ctl…"   55 seconds ago   Up 54 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   myweb

# WEB 접속 
$ curl localhost
okms1017 Web Server 1.0.0<br>
<pre>
    _    _______        ______    ____  _             _
   / \  | ____\ \      / / ___|  / ___|| |_ _   _  __| |_   _
  / _ \ |  _|  \ \ /\ / /\___ \  \___ \| __| | | |/ _` | | | |
 / ___ \| |___  \ V  V /  ___) |  ___) | |_| |_| | (_| | |_| |
/_/   \_\_____|  \_/\_/  |____/  |____/ \__|\__,_|\__,_|\__, |
                                                        |___/
</pre>

 

DockerHub의 계정(okms1017)으로 로그인합니다. 

해당 이미지를 DockerHub에 업로드합니다. 

 

# Docker image 태그 설정 
$ DHUB=okms1017
$ docker tag myweb:v1.0.0 $DHUB/myweb:v1.0.0
$ docker images
REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
okms1017/myweb   v1.0.0    04e2c155fe0c   20 minutes ago   238MB
myweb            v1.0.0    04e2c155fe0c   20 minutes ago   238MB

# DockerHub Login
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: okms1017
Password: ******
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded

# Docker image Upload
$ docker push $DHUB/myweb:v1.0.0
The push refers to repository [docker.io/okms1017/myweb]
5b251912086a: Pushed
106e8431b412: Mounted from library/ubuntu
v1.0.0: digest: sha256:ecb1b752314a6c01ea07fe60d141a249ad6420b7a35f56bfe54fa5202d063e0c size: 741

 

DockerHub Upload - okms1017/myweb
okms1017/myweb tag - v1.0.0

 

DockerHub의 컨테이너를 실행하여 웹 접속이 잘 되는지 확인합니다. 

 

# Remove running container
$ docker rm -f myweb
myweb
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# Remove docker image(okms1017/myweb)
$ docker rmi $DHUB/myweb:v1.0.0
Untagged: okms1017/myweb:v1.0.0
Untagged: okms1017/myweb@sha256:ecb1b752314a6c01ea07fe60d141a249ad6420b7a35f56bfe54fa5202d063e0c
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
myweb        v1.0.0    04e2c155fe0c   39 minutes ago   238MB

# Excute DockerHub image
$ docker run -d -p 80:80 --rm --name myweb $DHUB/myweb:v1.0.0
Unable to find image 'okms1017/myweb:v1.0.0' locally
v1.0.0: Pulling from okms1017/myweb
Digest: sha256:ecb1b752314a6c01ea07fe60d141a249ad6420b7a35f56bfe54fa5202d063e0c
Status: Downloaded newer image for okms1017/myweb:v1.0.0
16c20955cb4379b42f4a327d9fec100e593a3a9c4f4e9e286bd2de4d704684a8
$ docker images
REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
okms1017/myweb   v1.0.0    04e2c155fe0c   41 minutes ago   238MB
myweb            v1.0.0    04e2c155fe0c   41 minutes ago   238MB
$ docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED              STATUS          PORTS                               NAMES
16c20955cb43   okms1017/myweb:v1.0.0   "usr/sbin/apache2ctl…"   About a minute ago   Up 59 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   myweb

# WEB 접속
$ curl -s ipinfo.io/ip | awk '{ print "myweb = http://"$1"" }'
myweb = http://43.201.86.29

 

WEB 접속 성공 1

 


2. EKS CI - Jenkins 

Jenkins 란? 

Jenkins는 지속적 통합(Continuous Integration, CI) 및 지속적 배포(Continuous Deploymentm, CD)를 지원하는 오픈소스 자동화 도구입니다. 

  • CI : 코드의 변경 사항이 발생할 때마다 자동으로 빌드하고 테스트합니다. 
  • CD : 빌드/테스트 완료 이후 아티팩트를 자동으로 운영환경에 배포하도록 지원합니다. 
  • 작업 스케줄링 : 예약된 시간에 빌드/테스트 작업이 실행되도록 할 수 있습니다. 
  • 플러그인 확장 : 빌드/배포 자동화를 위한 수백 개의 확장 플러그인을 제공합니다. 
    • 빌드 플러그인 : Maven, Ant, Gradle
    • VCS 플러그인 : Git, SVN
    • Language 플러그인 : Java, Python, Node.js  
  • Java 기반으로 서블릿 컨테이너 내부에서 구동되는 시스템입니다. 

 

Jenkins 설치 및 설정 

LTS 제공: Jenkins Download

 

Amazon Corretto 17 버전으로 JAVA 설치를 진행합니다. 

 

* Amazon Corretto 17 이란?

- AWS에서 제공하는 OpenJDK 17의 LTS 배포판입니다. 

- Linux, Windows, macOS 등 운영체제를 지원합니다. 

 

# Add required dependencies for the jenkins package
$ sudo yum -y install fontconfig java-17-amazon-corretto

# JAVA 버전 확인 
$ java -version
openjdk version "17.0.10" 2024-01-16 LTS
OpenJDK Runtime Environment Corretto-17.0.10.8.1 (build 17.0.10+8-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.10.8.1 (build 17.0.10+8-LTS, mixed mode, sharing)

# JAVA 설치경로 확인
$ alternatives --display java
java - status is auto.
 link currently points to /usr/lib/jvm/java-17-amazon-corretto.x86_64/bin/java
/usr/lib/jvm/java-17-amazon-corretto.x86_64/bin/java - priority 17100801
 slave java-17-amazon-corretto: /usr/lib/jvm/java-17-amazon-corretto.x86_64
 slave jre: /usr/lib/jvm/java-17-amazon-corretto.x86_64
 slave jre_openjdk: /usr/lib/jvm/java-17-amazon-corretto.x86_64
 slave keytool: /usr/lib/jvm/java-17-amazon-corretto.x86_64/bin/keytool
 slave rmiregistry: /usr/lib/jvm/java-17-amazon-corretto.x86_64/bin/rmiregistry
 slave java.1: /usr/lib/jvm/java-17-amazon-corretto.x86_64/man/man1/java.1
 slave keytool.1: /usr/lib/jvm/java-17-amazon-corretto.x86_64/man/man1/keytool.1
 slave rmiregistry.1: /usr/lib/jvm/java-17-amazon-corretto.x86_64/man/man1/rmiregistry.1
Current `best' version is /usr/lib/jvm/java-17-amazon-corretto.x86_64/bin/java.

# 환경변수 설정 
$ JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto.x86_64
$ echo $JAVA_HOME
/usr/lib/jvm/java-17-amazon-corretto.x86_64

 

Jenkins 설치를 진행합니다. 

 

# Jenkins 설치 
$ wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
$ rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
$ yum upgrade 
$ yum -y install jenkins 
$ systemctl daemon-reload
$ systemctl enable jenkins && sudo systemctl start jenkins
$ systemctl status jenkins 
● jenkins.service - Jenkins Continuous Integration Server
   Loaded: loaded (/usr/lib/systemd/system/jenkins.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2024-04-20 11:22:12 KST; 37s ago
 Main PID: 29110 (java)
    Tasks: 52
   Memory: 1.1G
   CGroup: /system.slice/jenkins.service
           └─29110 /usr/bin/java -Djava.awt.headless=true -jar /usr/share/java/jenkins.war --webroot=%C/jenkins/war --httpPort=8080

# 초기 비밀번호 확인 
$ cat /var/lib/jenkins/secrets/initialAdminPassword

# WEB 접속 URL
$ curl -s ipinfo.io/ip | awk '{ print "Jenkins = http://"$1":8080" }'
Jenkins = http://43.201.86.29:8080

 

설치가 완료되면 웹 주소로 접속하여 초기 비밀번호를 입력합니다. 

 

초기 비밀번호 입력

 

이어서 권장 플러그인 설치를 진행합니다. 

 

권장 플러그인 설치 1
권장 플러그인 설치 2

 

관리자 계정(admin)을 생성합니다. 

 

관리자 계정 생성

 

관리자 계정으로 Jenkins에 접속합니다. 

 

Jenkins Dashboard

 

[Jenkins 관리] > [Tools] 로 이동하여 JDK 경로를 설정합니다. 

 

Jenkins 관리 - Tools
JDK 경로 설정

 

Jenkins 기본 사용

[새로운 Item] > [Freestyle project] 를 생성합니다. 

 

프로젝트 생성 (Freestyle project)

 

[Build Steps] 는  빌드 시 단계별로 수행할 작업을 설정하는 항목입니다. 

여러 개의 'Build Step'을 추가할 수 있습니다. 

 

간단한 문장이 출력될 수 있도록 명령줄을 입력해봅니다. 

 

Build Steps
Build Steps - Execute shell

 

좌측의 [지금 빌드] 를 실행하면 고유 빌드 번호가 부여됩니다. 

고유 빌드 번호의 콘솔 출력(Console Output)을 확인합니다. 

 

지금 빌드 - Build History
Console Output 1

 

'Build Step'에 명령어를 추가로 몇 줄 더 입력하고 빌드합니다. 

 

Build Steps - 명령어 추가
Console Output 2

터미널에서 Jenkins 워크스페이스를 확인합니다. 

 

Jenkins Workspace

 

Jenkins Docker Build 

Jenkins로 도커 이미지를 빌드하고 컨테이너를 실행해봅니다. 

우선, Jenkins 계정으로 도커를 사용할 수 있도록 설정합니다. 

 

# Jenkins 계정: bash shell 설정 
$ grep -i jenkins /etc/passwd
jenkins:x:995:991:Jenkins Automation Server:/var/lib/jenkins:/bin/false
$ usermod -s /bin/bash jenkins
$ grep -i jenkins /etc/passwd
jenkins:x:995:991:Jenkins Automation Server:/var/lib/jenkins:/bin/bash

# Jenkins 계정: 도커 사용 권한 부여 
$ su - jenkins
$ docker info 
Server:
ERROR: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/info": dial unix /var/run/docker.sock: connect: permission denied
$ exit

$ chmod 666 /var/run/docker.sock
ll -d /var/run/docker.sock
srw-rw-rw- 1 root docker 0 Apr 19 22:51 /var/run/docker.sock
$ usermod -aG docker jenkins
$ cat /etc/group | grep docker
docker:x:992:jenkins

$ su - jenkins
$ docker info 
```
Server:
 Containers: 1
  Running: 1
  Paused: 0
  Stopped: 0
 Images: 5
 Server Version: 20.10.25
 Storage Driver: overlay2
```

# Jenkins 계정: DockerHub 로그인 
$ docker login
Login Succeeded

 

Jenkins 홈 디렉터리 하위에 도커파일을 생성합니다. 

 

# 디렉토리 생성
$ mkdir -p ~/myweb2 && cd ~/myweb2
$ pwd
/var/lib/jenkins/myweb2

# Dockerfile 생성
$ vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.0.0 NICK=okms1017
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
    sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
    apt-get update && apt-get install -y apache2 figlet && \
    echo "$NICK Web Server $VERSION<br>" > /var/www/html/index.html && \
    echo "<pre>" >> /var/www/html/index.html && \
    figlet AEWS Study >> /var/www/html/index.html && \
    echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]

 

Jenkins를 이용하여 자동 빌드/배포하고 결과를 확인합니다. 

 

Build Step 1. 도커 이미지 빌드
Build Step 2. 도커허브 업로드
Build Step 3. 도커 컨테이너 실행
빌드/배포 모니터링
WEB 접속 성공 2

 

Poll SCM 

Poll SCM은 깃허브 레포지토리의 변경사항을 주기적으로 확인하여 CI 빌드를 트리거하는 기능입니다. 

 

새로운 프로젝트(Trigger-Project)를 생성하여 깃허브 레포지토리와 연동합니다. 

 

Jenkins - GitHub 레포지토리 연동
Branch - main

 

Sparse Checkout paths 항목은 연동한 레포지토리의 하위 디렉토리 중 경로가 일치하는 디렉토리('1')를 감시하는 기능입니다. 

 

Sparse Checkout paths
GitHub 레포지토리 - 디렉토리 '1'

 

빌드 매개변수를 설정합니다. 

 

  • VERSION : v1.0.0
  • NICK : okms1017

매개변수 (VERSION)
매개변수 (NICK)

 

매분마다 'aews-cicd' 레포지토리의 '1' 디렉토리를 확인하여 소스코드의 변경사항이 발생한 경우 빌드를 실행하도록 Poll SCM을 설정합니다. 

 

Poll SCM

 

레포지토리로부터 새로운 소스코드를 내려받아 빌드/배포하도록 'Build Steps'를 구성합니다. 

 

Build Step 1. Dockerfile 다운로드
Build Step 2. 빌드 및 배포

 

로컬에서 기존 소스코드의 VERSION 정보 값을 v1.1.0으로 변경하여 Commit/Push를 수행합니다. 

 

 

'aews-cicd/1/Dockerfile'에 소스코드 변경사항이 정상적으로 반영된 모습입니다. 

 

VERSION = 1.1.0

 

그러나 Jenkins에서 빌드에 실패한 모습입니다. 

왜냐하면 'Build Step'을 시작할 때마다 프로젝트 워크스페이스 경로(/var/lib/jenkins/workspace/Trigger-Project)로 이동하기 때문입니다. 

해당 에러는 현재 경로에서 Dockerfile을 찾지 못했을 경우 발생하는 에러입니다. 

 

Console Output - Build Failure

 

'Build Step 2'를 다음과 같이 수정합니다. 

 

Build Step 2 경로 변경 명령어 추가

 

소스코드의 VERSION 정보 값을 v1.2.0으로 변경하여 Commit/Push를 수행합니다. 

'aews-cicd/1/Dockerfile'에 소스코드 변경사항(VERSION=1.2.0)이 정상적으로 반영되었습니다. 

 

VERSION = 1.2.0

Jenkins 빌드 또한 성공 메시지(SUCCESS)가 뜹니다. 

 

그러나 실제로는 Dockerfile의 VERSION 변수 값(1.2.0)과 Jenkins의 VERSION 매개변수 값(1.0.0)이 일치하지 않습니다. 

따라서 컨텐츠는 v1.2.0이지만 빌드된 이미지는 v1.0.0으로 태깅됩니다.  

 

기존 이미지는 좀비 이미지마냥 태그를 잃었습니다. 

 

버전별로 이미지가 빌드되도록 Jenkins의 VERSION 매개변수 값(1.2.0)을 넣어 '파라미터와 함께 빌드' 합니다. 

 

파라미터와 함께 빌드 (VERSION=v1.2.0)

정상적으로 태깅이 되고 화면이 뜨는 모습입니다. 

 

WEB 접속 성공 3

 

Jenkins Pipeline 

Jenkins에 CD 파이프라인을 구현하고 통합하는 것을 지원하는 플러그인 스크립트 모음입니다. 

 

Jenkins Pipeline

  • 파이프라인 장점 
    • 코드 : 어플리케이션의 CI/CD 프로세스를 코드 형식으로 작성할 수 있고, 깃허브와 연동하여 팀원과 공유 및 협업이 가능합니다. 
    • 내구성 : Jenkins 서버가 의도적으로 또는 우발적으로 재시작되더라도 문제없이 유지됩니다. 
    • 일시 중지 : 파이프라인을 실행하는 도중 사람의 승인이나 입력을 기다리기 위해 중단(대기)가 가능합니다. 
    • 다양성 : 분기나 반복, 병렬 처리와 같은 다양한 CI/CD 요구사항을 지원합니다. 
  • 파이프라인 용어
    • 파이프라인 : 전체 빌드 프로세스를 정의하는 코드
    • 노드 : 파이프라인을 실행하는 시스템
    • 스테이지 : 특정 단계에서 수행되는 작업들의 정의
    • 스텝 : 특정 단계에서 수행되는 단일 작업을 의미 
  • 파이프라인 3가지 구성 형태

1. Pipeline Script : Jenkins 대시보드에서 파이프라인을 생성하고 셸 스크립트를 직접 작성하여 빌드하는 방식입니다.  

Pipeline Script

2. Pipeline Script from SCM : 사전에 작성한 JenkinsFile을 형상관리 저장소에 보관하고 빌드 시작 시 파이프라인 프로젝트에서 호출하는 방식입니다. 

Pipeline Script from SCM

3. Blue Ocean : UI 기반으로 파이프라인을 시각적으로 구성하면 자동으로 JenkinsFile이 생성되어 실행되는 방식입니다. 

Blue Ocean

  • 파이프라인 2가지 구문 : 선언형 (권장) / 스크립트형 

- 선언형 파이프라인 (Declarative) : 작성 용이, 최근 문법, Step 필수 

 

pipeline {
    agent any     # Execute this Pipeline or any of its stages, on any available agent.
    stages {
        stage('Build') {   # Defines the "Build" stage.
            steps {
                //         # Perform some steps related to the "Build" stage.
            }
        }
        stage('Test') { 
            steps {
                // 
            }
        }
        stage('Deploy') { 
            steps {
                // 
            }
        }
    }
}

 

- 스크립트형 파이프라인 (Scripted) : 커스텀 용이, 복잡(난이도 ↑), Step 옵션 

 

node {          #  Execute this Pipeline or any of its stages, on any available agent.
    stage('Build') {    # Defines the "Build" stage. stage blocks are optional in Scripted Pipeline syntax. However, implementing stage blocks in a Scripted Pipeline provides clearer visualization of each stage's subset of tasks/steps in the Jenkins UI.
        //              # Perform some steps related to the "Build" stage.
    }
    stage('Test') { 
        // 
    }
    stage('Deploy') { 
        // 
    }
}

 

Pipeline Script

  • Hello World 테스트 

pipeline {
    agent any

    stages {
        stage('정보 확인') {
            steps {
                echo 'Hello World'
                sh 'java -version'
            }
        }
        stage('가라 배포') {
            steps {
                echo "Deployed successfully!";
            }
        }
    }
}

  • 환경변수 사용, 문자열 보간 
pipeline {
    agent any
    environment { 
        STUDYNAME = 'AEWS'
    }
    stages {
        stage('연습') {
            environment { 
                mykey = 'abcd'
            }
            steps {
                echo "${STUDYNAME}";
                sh 'echo ${mykey}'
            }
        }
    }
}

  • tools : maven_3.8.7 
pipeline {
    agent any
    tools {
        maven 'maven_3.8.7' 
    }
    stages {
        stage('Example') {
            steps {
                sh 'mvn --version'
            }
        }
    }
}

Jenkins 관리> Tools> Maven installations

  • Tools : jdk-17 
pipeline {
    agent any
    tools {
        jdk 'jdk-17' 
    }
    stages {
        stage('툴 지정') {
            steps {
                sh 'java -version'
            }
        }
    }
}

  • Triggers : 매분마다 'Hello World' 출력하기 
pipeline {
    agent any
    triggers {
        cron('* * * * *')
    }
    stages {
        stage('주기 반복') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

주기 반복

  • Parameters : Key-Value String, Choice[a,b,c,...] 
pipeline {
    agent any
    parameters {
        string(name: 'PERSON', defaultValue: 'okms1017', description: 'Who are you?')
        choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')
    }
    stages {
        stage('파라미터 사용') {
            steps {
                echo "Hello ${params.PERSON}"
                echo "Choice: ${params.CHOICE}"
            }
        }
    }
}

  • post (빌드 후 조치) 설정
    • always : 항상 실행
    • changed : 현재 빌드가 이전 빌드와 다를 시 실행
    • success : 현재 빌드 성공 시 실행 
    • failure : 현재 빌드 실패 시 실행
    • unstable : 현재 빌드의 상태가 불안정하면 실행 
pipeline {
    agent any
    stages {
        stage('배포 후 빌드 후 조치 결과 출력') {
            steps {
                echo 'Hello World'
            }
        }
    }
    post { 
        always { 
            echo 'Always say Hello World!'
        }
    }
}

  • post 조치 항목에 대한 메시지 출력 
pipeline {
    agent any
    stages {
        stage('Compile') {
            steps {
                echo "Compiled successfully!";
            }
        }

        stage('JUnit') {
            steps {
                echo "JUnit passed successfully!";
            }
        }

        stage('Code Analysis') {
            steps {
                echo "Code Analysis completed successfully!";
            }
        }

        stage('Deploy') {
            steps {
                echo "Deployed successfully!";
            }
        }
    }

    post {
      always {
        echo "This will always run"
      }
      success {
        echo "This will run when the run finished successfully"
      }
      failure {
        echo "This will run if failed"
      }
      unstable {
        echo "This will run when the run was marked as unstable"
      }
      changed {
        echo "This will run when the state of the pipeline has changed"
      }
    }
}

  • Snippet Generator 사용하기 : Pipeliine Syntax> Snippet Generator> sh: Shell Script

Snippet Generator

* Snippet Generator 란?

- JenkinsFile, Jenkins Script 작성 시, 필요한 작업에 대한 명확한 구문을 제공하는 도구입니다. 

 

Jenkins Pipeline with SCM 

Pipeline에 깃허브 레포지토리를 연동합니다. 

'okms1017/aews-cicd/2/' 디렉토리에 존재하는 Jenkinsfile을 가져와서 파이프라인을 실행합니다. 

 

Pipeline Script from SCM
JenkinsFile
Pipeline with SCM 실행 결과

Started by user okms1017
Obtained 2/Jenkinsfile from git https://github.com/okms1017/aews-cicd.git
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/lib/jenkins/workspace/Pipeline with SCM
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Checkout SCM)
[Pipeline] checkout
The recommended git tool is: NONE
No credentials specified
Cloning the remote Git repository
Using no checkout clone with sparse checkout.
Cloning repository https://github.com/okms1017/aews-cicd.git
 > git init /var/lib/jenkins/workspace/Pipeline with SCM # timeout=10
Fetching upstream changes from https://github.com/okms1017/aews-cicd.git
 > git --version # timeout=10
 > git --version # 'git version 2.40.1'
 > git fetch --tags --force --progress -- https://github.com/okms1017/aews-cicd.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git config remote.origin.url https://github.com/okms1017/aews-cicd.git # timeout=10
 > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
Avoid second fetch
 > git rev-parse refs/remotes/origin/main^{commit} # timeout=10
Checking out Revision 4d520eb8900e30c698fff060e38ea88fa0d2be62 (refs/remotes/origin/main)
 > git config core.sparsecheckout # timeout=10
 > git config core.sparsecheckout true # timeout=10
 > git read-tree -mu HEAD # timeout=10
 > git checkout -f 4d520eb8900e30c698fff060e38ea88fa0d2be62 # timeout=10
Commit message: "Update version information"
First time build. Skipping changelog.
[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Compile)
[Pipeline] echo
Compiled successfully!
[Pipeline] sh
+ sleep 1
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (JUnit)
[Pipeline] echo
JUnit passed successfully!
[Pipeline] sh
+ sleep 1
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Code Analysis)
[Pipeline] echo
Code Analysis completed successfully!
[Pipeline] sh
+ sleep 1
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] echo
Deployed successfully!
[Pipeline] sh
+ sleep 1
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] echo
This will always run
[Pipeline] echo
This will run when the state of the pipeline has changed
[Pipeline] echo
This will run when the run finished successfully
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

 

Secret Text

암호가 JenkinsFile에 노출되지 않게 하는 기능입니다. 

  • 평문 (비권장)

pipeline {
    agent any

    stages {
        stage('remote ssh') {
            steps {
                sh 'sshpass -p qwe123 ssh root@192.168.1.100 hostname'
            }
        }
    }
}

  • Credentials (권장) : Jenkins 관리> Credentials> System> Global credentials (unrestricted)

Secret text

파이프라인 스크립트를 작성하여 관리용 인스턴스(bastion)에 접속해봅니다. 

 

pipeline {
    agent any
    environment {
        SSHPW_CREDS = credentials('vmsshpw')
    }

    stages {
        stage('remote ssh') {
            steps {
                sh('echo ${SSHPW_CREDS}')
                sh('sshpass -p $SSHPW_CREDS ssh root@192.168.1.100 hostname')
            }
        }
    }
}

 

# Amazon Linux 2 
# epel repository 설치
$ amazon-linux-extras install epel
$ yum repolist
repo id                               repo name
amzn2extra-epel/2/x86_64              Amazon Extras repo for epel

# sshpass 설치 
$ yum -y install sshpass
$ sshpass
Usage: sshpass [-f|-d|-p|-e] [-hV] command parameters
   -f filename   Take password to use from file
   -d number     Use number as file descriptor for getting password
   -p password   Provide password as argument (security unwise)
   -e            Password is passed as env-var "SSHPASS"
   With no parameters - password will be taken from stdin

   -P prompt     Which string should sshpass search for to detect a password prompt
   -v            Be verbose about what you're doing
   -h            Show help (this screen)
   -V            Print version information

 

 

Secret Files 

키파일을 JenkinsFile에 노출되지 않게 하는 기능입니다. 

 

kube config 파일을 로컬 PC에 복사합니다. 

 

> scp root@[작업용EC2_공인IP]:/root/.kube/config .

 

 

kube config 파일을 Jenkins 서버에 업로드합니다. 

Jenkins 관리> Credentials> System> Global credentials (unrestricted)

 

Secret file

Jenkins 계정으로 kubectl 명령어를 실행하는 파이프라인 스크립트입니다. 

사전에 Jenkins 계정의 자격 증명이 되어 있어야 합니다. 

 

pipeline {
    agent any
    environment {
        MY_KUBECONFIG = credentials('k8sconfig')
    }

    stages {
        stage('remote k8s api') {
            steps {
                sh("kubectl --kubeconfig $MY_KUBECONFIG get pods -A")
                sh("kubectl --kubeconfig $MY_KUBECONFIG run nginx --image nginx --port=80")
            }
        }
    }
}

 

Jenkins with Kubernetes

Jenkins 계정 디렉토리 하위에 kube config 파일을 복사하고 자격증명을 진행합니다. 

 

$ mkdir ~/.kube

# cp ~/.kube/config /var/lib/jenkins/.kube/config
# chown jenkins:jenkins /var/lib/jenkins/.kube/config

$ aws configure

 

Jenkins에서 CI/CD 파이프라인을 구성하여 디플로이먼트와 서비스를 배포해봅니다. 

 

pipeline {
    agent any

    tools {
        jdk 'jdk-17'
    }

    environment {
        DOCKERHUB_USERNAME = 'okms1017'
        GITHUB_URL = 'https://github.com/okms1017/aews-cicd.git'
        // deployment-svc.yaml -> image: okms1017/myweb:v1.0.0        
        DIR_NUM = '3'
    }

    stages {
        stage('Container Build') {
            steps {
                // 릴리즈파일 체크아웃
                checkout scmGit(branches: [[name: '*/main']], 
                    extensions: [[$class: 'SparseCheckoutPaths', 
                    sparseCheckoutPaths: [[path: "/${DIR_NUM}"]]]], 
                    userRemoteConfigs: [[url: "${GITHUB_URL}"]])

                // 컨테이너 빌드 및 업로드
                sh "docker build -t ${DOCKERHUB_USERNAME}/myweb:v1.0.0 ./${DIR_NUM}"
                sh "docker push ${DOCKERHUB_USERNAME}/myweb:v1.0.0"
            }
        }

        stage('K8S Deploy') {
            steps {
                sh "kubectl apply -f ./${DIR_NUM}/deploy/deployment-svc.yaml"
            }
        }
    }
}

 

 

이번에는 로컬에서 디플로이먼트의 파드 수를 4 →10으로 변경한 후 Commit/Push를 수행합니다. 

그리고 파이프라인을 재실행하여 파드의 변화를 모니터링합니다. 

 

접속 테스트용 파드를 하나 배포하고 웹 접속을 테스트합니다. 

 

# netpod 배포

$ cat <<EOF | kubectl create -f -

apiVersion: v1

kind: Pod

metadata:

  name: netpod

  labels:

    app: pod

spec:

  containers:

  - name: netshoot-pod

    image: nicolaka/netshoot

    command: ["tail"]

    args: ["-f", "/dev/null"]

  terminationGracePeriodSeconds: 0

EOF

 

# netpod -> WEB 반복 접속
$ while true; do kubectl exec -it netpod -- curl myweb:8080 | grep Web; echo; done
aews Web Server 1.0.0<br>
aews Web Server 1.0.0<br>
aews Web Server 1.0.0<br>
aews Web Server 1.0.0<br>
aews Web Server 1.0.0<br>
aews Web Server 1.0.0<br>

# Workspace 확인
$ tree /var/lib/jenkins/workspace/
/var/lib/jenkins/workspace/
├── Docker-Project
├── First-Project
│   └── aews.txt
├── Pipeline
│   └── 3
│       ├── deploy
│       │   └── deployment-svc.yaml
│       └── Dockerfile
├── Pipeline@tmp
│   └── secretFiles
├── Pipeline\ with\ SCM
│   └── 2
│       └── Jenkinsfile
├── Pipeline\ with\ SCM@tmp
└── Trigger-Project
    └── 1
        └── Dockerfile
$ cat /var/lib/jenkins/workspace/Pipeline/3/Dockerfile
Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul MYVERSION=1.0.0 NICK=aews
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
    sed -i 's/archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list && \
    apt-get update && apt-get install -y apache2 figlet && \
    echo "$NICK Web Server $MYVERSION<br>" > /var/www/html/index.html && \
    echo "<pre>" >> /var/www/html/index.html && \
    figlet AEWS Study >> /var/www/html/index.html && \
    echo "</pre>" >> /var/www/html/index.html
EXPOSE 80
CMD ["usr/sbin/apache2ctl", "-DFOREGROUND"]

 

 


[출처]

1) CloudNet@, AEWS 실습 스터디

2) https://www.jenkins.io/

 

Jenkins

Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software

www.jenkins.io

3) https://www.jenkins.io/doc/book/installing/linux/#red-hat-centos

 

Linux

Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software

www.jenkins.io

4) https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/amazon-linux-install.html

 

Amazon Corretto 17 Installation Instructions for Amazon Linux 2 and Amazon Linux 2023 - Amazon Corretto 17

Amazon Corretto 17 Installation Instructions for Amazon Linux 2 and Amazon Linux 2023 This topic describes how to install and uninstall Amazon Corretto 17 on a host or container running the Amazon Linux 2 or Amazon Linux 2023 operating systems. Option 1: I

docs.aws.amazon.com

5) https://www.jenkins.io/doc/book/pipeline/

 

Pipeline

Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software

www.jenkins.io

6) https://www.jenkins.io/doc/book/blueocean/pipeline-run-details/

 

Pipeline Run Details View

Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software

www.jenkins.io

7) https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#secret-text

 

Using a Jenkinsfile

Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software

www.jenkins.io

8) https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#secret-files

 

Using a Jenkinsfile

Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software

www.jenkins.io

728x90

'AWS > EKS' 카테고리의 다른 글

[AEWS2] 8-1. What is Terraform ?  (2) 2024.04.28
[AEWS2] 7-2. EKS CI/CD - ArgoCD  (0) 2024.04.21
[AEWS2] 6-5. Kyverno  (0) 2024.04.13
[AEWS2] 6-4. OWASP Kubernetes Top 10  (0) 2024.04.13
[AEWS2] 6-3. EKS IRSA & Pod Identity  (0) 2024.04.13