본문 바로가기
Kubernetes/AWS EKS Workshop Study

7주차 1편 EKS CI/CD - Docker, Jenkin

by 개발자 영만 2024. 4. 21.

Docker

웹 서버 도커 이미지 생성 후 도커 컨테이너 실행

  • Dockerfile  파일 생성
# ubuntu 이미지 다운로드
docker pull ubuntu:20.04
docker images

# Dockerfile 파일 생성
vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=1.0.0 NICK=<자신의 닉네임>
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"]

 

  • 이미지 빌드 및 컨테이너 실행
# 이미지 빌드
cat Dockerfile
docker build -t myweb:v1.0.0 .
docker images
docker image history myweb:v1.0.0
docker image inspect myweb:v1.0.0 | jq

# 컨테이너 실행
docker run -d -p 80:80 --rm --name myweb myweb:v1.0.0
docker ps
curl localhost

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

  • 도커 허브 업로드
#
DHUB=<도커 허브 계정>
docker tag myweb:v1.0.0 $DHUB/myweb:v1.0.0
docker images

# 도커 허브 로그인
docker login
Username: <자신의 ID>
Password: <암호>

## 로그인 정보는 /[계정명]/.docker/config.json 에 저장됨. docker logout 시 삭제됨
cat /root/.docker/config.json | jq

# push 로 이미지를 저장소에 업로드
docker push $DHUB/myweb:v1.0.0

 

  • 해당 저장소 이미지 활용
# 
docker run -d -p 80:80 --rm --name myweb $DHUB/myweb:v1.0.0
docker images

# 확인
docker ps
curl localhost
curl -s ipinfo.io/ip | awk '{ print "myweb = http://"$1"" }'

 

Jenkins

Jenkins 소개

  • Jenkins를 사용하여 CI/CD 워크플로우를 효과적으로 구축하고 관리할 수 있습니다.
    • 코드 가져오기: Jenkins는 VCS(Version Control System) 플러그인을 통해 중앙 코드 리포지터리에서 최신 코드를 가져옵니다. 이 예제에서는 Git을 사용한다고 가정합니다.
    • 단위 테스트 실행: Jenkins는 코드를 가져온 후에 단위 테스트를 실행합니다. 이를 통해 코드 변경 사항이 이전에 작성된 테스트 케이스와 충돌하지 않는지 확인합니다.
    • 코드 빌드: Jenkins는 코드를 컴파일하고 빌드합니다. 이 단계에서는 코드를 실행 가능한 소프트웨어로 변환합니다.
    • 코드 배포: 빌드된 애플리케이션을 배포합니다. 이 단계에서는 프로덕션 환경 또는 테스트 환경과 같은 다양한 환경으로 애플리케이션을 배포합니다.
    • E-E 테스트 실행: Jenkins는 Selenium과 같은 도구를 사용하여 End-to-End(종단간) 테스트를 실행합니다. 이를 통해 애플리케이션의 전체적인 동작을 확인하고 사용자 인터페이스를 자동화하여 테스트합니다.
  • 위 단계들을 Jenkins의 파이프라인 기능을 사용하여 스크립트로 작성할 수 있습니다. 이를 통해 각 단계가 순차적이고 종속적으로 실행되며, 특정 단계에서 실패할 경우 이후 단계가 실행되지 않도록 할 수 있습니다.
  • Jenkins는 다양한 플러그인을 지원하여 Maven, Ant, Git, SVN, Java, Python, Node.js 등과 같은 다양한 도구와 언어를 연동할 수 있습니다.

설치 및 설정

  • Jenkins 설치
# Add required dependencies for the jenkins package
# https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/amazon-linux-install.html
sudo yum install fontconfig java-17-amazon-corretto -y
java -version
alternatives --display java
JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto.x86_64
echo $JAVA_HOME

# 젠킨스 설치
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
sudo yum upgrade
sudo yum install jenkins -y
sudo systemctl daemon-reload
sudo systemctl enable jenkins && sudo systemctl start jenkins   # 다소 시간 걸림
sudo systemctl status jenkins

# 초기 암호 확인
sudo systemctl status jenkins
cat /var/lib/jenkins/secrets/initialAdminPassword

# 접속 주소 확인 
curl -s ipinfo.io/ip | awk '{ print "Jenkins = http://"$1":8080" }'

 

  • 초기 암호 입력

 

  • 플러그인 설치

 

  • 관리자 계정 설정 : 계정명, 암호, 이름

 

  • 설정 완료 후 젠킨스 접속
    • item : 젠킨스에서 사용하는 작업의 최소 단위
    • 사람 : 계정 관련
    • Jenkins 관리 : 전역 설정 등

 

기본 사용, Tools 설정

  • Jenkins 관리 → Tools 진입

 

  • JDK installations
    • Add JDK 클릭 → Name : jdk-17, JAVA_HOME : /usr/lib/jvm/java-17-amazon-corretto.x86_64

 

  • 첫번째 Item(Project) 생성
    • 새로운 Item 클릭 → Name : First-Project , Freestyle project

 

  • Build Steps → Add build step → Execute shell 클릭

 

  • 간단한 문장 출력 될 수 있게 입력 : echo "Aws Workshop Study" → 하단 Apply 후 저장

 

  • 지금 빌드 클릭

 

  • 빌드 결과 확인 : 화살표 클릭 후 Console Output 클릭

 

  • 콘솔 출력 확인 : 하단에 SUCCESS 확인

 

  • 상위 메뉴 - 구성 : 아래 명령어 한줄 추가 java -version → Apply 저장
    • 한줄 더 추가 : whoami
    • 한줄 더 추가 : touch hello.txt

 

  • 최상위 - 프로젝트 화살표 선택 → 지금 빌드
    • 이후 콘솔 출력 확인

 

  • Item(Job) 프로젝트 디텍토리 확인 : 혹은 젠킨스 작업 공간 확인

 

Docker 사용 : Docker-Project

  • 사전 준비
# jenkins 유저로 docker 사용 가능하게 설정
usermod -s /bin/bash jenkins
grep -i jenkins /etc/passwd

#
chmod 666 /var/run/docker.sock
usermod -aG docker jenkins

# Jeknins 유저로 확인
su - jenkins
docker info

# Dockerhub로 로그인 하기
docker login
Username: <자신의 계정명>
Password: <자신의 암호>

# myweb:v2.0.0 컨테이너 이미지 생성을 위한 Dockerfile 준비
# 실습을 위한 디렉터리 생성 및 이동
mkdir -p ~/myweb2 && cd ~/myweb2

# Dockerfile 파일 생성
vi Dockerfile
FROM ubuntu:20.04
ENV TZ=Asia/Seoul VERSION=2.0.0 NICK=<자신의 닉네임>
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"]

 

  • item : Docker-Project , freestyle

  • Build Steps : Execute shell
cd /var/lib/jenkins/myweb2
docker build -t myweb:v2.0.0 .
  • Add build Steps : Execute shell
docker run -d -p 80:80 --rm --name myweb myweb:v2.0.0

 

  • 지금 빌드 → 확인
docker images
docker ps
curl localhost

 

파라미터, 빌드 유발(SCM - Git) 사용 : Trigger-Project

  • Item : Trigger-Project, freestyle
  • 빌드 매개변수 : String
    • 변수명 : VERSION, Default Vault : v1.0.0
    • 변수명 : NICK, Default Vault : <자신의 계정명>

 

 

  • 빌드 유발 : Poll SCM (* * * * *)

 

  • Build Steps : Execute shell

 

  • 자신의 Github Repo 1 에서 Dockerfile에 VERSION 정보를 수정 후 Commit → 1분 정도 후에 젠킨스에서 확인

 

  • 파라미터와 함께 빌드 클릭 → 아래 입력 후 확인

 

파이프라인

  • 파이프라인 장점
    • 코드 : 애플리케이션 CI/CD 프로세스를 코드 형식으로 작성할 수 있고, 해당 코드를 중앙 리포지터리에 저장하여 팀원과 공유 및 작업 가능
    • 내구성 : 젠킨스 서비스가 의도적으로 또는 우발적으로 재시작되더라도 문제없이 유지됨
    • 일시 중지 가능 : 파이프라인을 실행하는 도중 사람의 승인이나 입력을 기다리기 위해 중단하거나 기다리는 것이 가능
    • 다양성 : 분기나 반복, 병렬 처리와 같은 다양한 CI/CD 요구 사항을 지원
  • 파이프라인 용어
    • 파이프라인 : 전체 빌드 프로세스를 정의하는 코드.
    • 노드 node : 파이프라인을 실행하는 시스템.
    • 스테이지 stage : 특정 단계에서 수행되는 작업들의 정의.
    • 스텝 step : 파이프라인의 특정 단계에서 수행되는 단일 작업을 의미.
  • 파이프라인 3가지 구성 형태
    • Pipeline script : 일반적인 방식으로 Jenkins 파이프라인을 생성하여 Shell Script를 직접 생성하여 빌드하는 방식
    • Pipeline script from SCM : 사전 작성한 JenkinsFile을 형상관리 저장소에 보관하고, 빌드 시작 시 파이프라인 프로젝트에서 호출 실행하는 방식
    • Blue Ocean 기반 : UI기반하여 시각적으로 파이프라인을 구성하면, JenkinsFile이 자동으로 생성되어 실행되는 방식
  • 파이프라인 2가지 구문 : 선언형 파이프라인(권장)과 스크립트형 파이프라인
    • 선언형 파이프라인 : 쉽게 작성 가능, 최근 문법이고 젠킨스에서 권장하는 방법, step 필수!
    • 스크립트형 파이프라인 : 커스텀 작업에 용이, 복잡하여 난이도가 높음, step은 필수 아님
  • 선언형 Declarative 파이프라인
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 파이프라인
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') { 
        // 
    }
}

 

Jenkins Pipeline : First-Pipeline

  • Item : First-Pipeline → Pipeline
  • Hello World 테스트
pipeline {
    agent any

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

  • 아래 처럼 수정 후 확인: 환경변수 사용, 문자열 보간 → Console Output 확인
pipeline {
    agent any
    environment { 
        STUDYNAME = 'AEWS'
    }
    stages {
        stage('연습') {
            environment { 
                mykey = 'abcd'
            }
            steps {
                echo "${STUDYNAME}";
                sh 'echo ${mykey}'
            }
        }
    }
}

  • 아래 처럼 수정 후 확인: Tools → Console Output 확인
pipeline {
    agent any
    tools {
        jdk 'jdk-17' 
    }
    stages {
        stage('툴 지정') {
            steps {
                sh 'java -version'
            }
        }
    }
}

  • 아래 처럼 수정 후 확인: 파이프라인 빌드 시작(트리거) → Console Output 확인
pipeline {
    agent any
    triggers {
        cron('* * * * *')
    }
    stages {
        stage('주기 반복') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

  • 아래 처럼 수정 후 확인: 파라미터와 함께 빌드 → Console Output 확인
pipeline {
    agent any
    parameters {
        string(name: 'PERSON', defaultValue: 'gasida', 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 (빌드 후 조치) → Console Output 확인
    • 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"
      }
    }
}