이번 보고서를 진행하며 Jenkins, Gitlab을 활용한 CI/CD 환경을 구축하려고 한다.
Jenkins - local, docker
Gitlab - Gachon Onpremise, docker
Nginx - Oracle Instance, docker
위와 같은 구조를 구축해본다. 구축 과정은 CI/ CD로 나누었다.
구축하려는 개념에 대해 이해하고 넘어가자.
CI/CD는 지속적인 통합 (Continuous Integration) 및 지속적인 전달 (Continuous Delivery)의 줄임말이다.
여러 개발자들이 함께 소프트웨어를 개발할 때 발생하는 문제들을 해결하기 위한 방법이다. CI는 소스 코드의 변경사항을 계속해서 통합하며 품질을 검증하고, 이 과정을 자동화한다.
여러 개발자들이 함께 작업하다보면 코드 충돌이나 버그가 발생할 수 있는데, CI는 이런 문제를 예방하기 위해 소스 코드의 변경을 자주 통합하고 자동으로 빌드하고 테스트하며 정적 분석을 수행한다.
CI의 확장된 개념으로, 개발된 소프트웨어를 신속하고 안정적으로 사용자에게 전달하는 것을 목표로 한다. CD는 자동화된 프로세스를 통해 개발한 소프트웨어를 테스트, 빌드, 패키지화하고 배포하는 것을 의미한다.
이를 통해 개발자들은 작은 단위로 빠르게 변경 사항을 배포하고 사용자들에게 신속하게 소프트웨어를 제공할 수 있다.
CI/CD를 관리하고 구축하는데 사용되는 도구로 Jenkins와 Gitlab을 사용하기로 하였다.
이러한 단계를 따르면 GitLab과 Jenkins 간의 CI/CD 파이프라인을 구축하여 코드 변경을 자동으로 테스트, 빌드, 배포할 수 있다. 또한 소스 코드, 설정 파일, 환경 변수 등을 작업 간에 공유하고 통합할 수도 있다.
일련의 과정을 수행해 보며 CI/CD 시스템을 구축해보고자 한다.
Local - Gitlab - Jenkins
◆ docker 및 docker-compose가 미리 설치되어 있어야 함. ✅
◆ 우선 원활한 설치를 위해 selinux설정을 disabled 함.✅
◆ /etc/seliux/config 에서 disabled 함.✅
젠킨스 컨테이너에 접속하여 초기 비밀번호 확인
Suggested Plugins 설치진행
(생각보다 시간이 조금 걸렸다)
Admin 설정
설치 인스턴스 ip : http://172.16.211.84
여기서는 무료버전인 gitlab-CE버전을 docker compose 기반으로 설치함.
docker compose설치
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
version: "3.6"
services:
gitlab:
image: "gitlab/gitlab-ce:latest"
restart: always
container_name: gitlab
hostname: "172.16.211.84"
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://172.16.211.84'
ports:
- "9090:80"
- "443:443"
- "1022:22"
volumes:
- "~/gitlab/config:/etc/gitlab"
- "~/gitlab/logs:/var/log/gitlab"
- "~/gitlab/data:/var/opt/gitlab"
- "~/gitlab/backups:/var/opt/gitlab/backups"
shm_size: "256m"
docker compose 파일을 작성하여 설치하였다
위 화면이 뜨기까지 아주 오랜 시간이 걸려 걱정했지만 결국 떴다..
비밀번호 변경 후 프로젝트 생성
◆ gitlab관련 플러그인을 설치함.
“Jenkins 관리”→“플러그인 관리”
새로운 아이템 생성
confidential에서 gitlab 관련 정보를 입력한다
GitLab webhook URL: http://localhost:8181/project/saproject-jm
“Build”탭에서 Add build step메뉴에서 “Execute shell”를 선택하고 save버튼으로 마무리한다.
빌드 확인시 아래와 같이 정상적으로 작동한다 (trouble shooting #1 발생)
◆ 우선 jenkins에서 아래와 같이 “빌드유발” 부분에서 고급버튼을 누르고
“Secret token”을 발생시킴. 이 토큰을 메모해놓고 gitlab시스템에 입력해야함.
jenkins - React Build - Nginx Mount
ref : https://crispyblog.kr/development/common/10#3-create-job
react는 NodeJS을 사용하여 빌드하므로 플러그인 설치가 필요하다
젠킨스 서버에서 클라우드 서버로 파일을 전송하기 위해선 ssh를 이용해 전달하는데, 젠킨스는 Publish Over SSH 플러그인을 통해 ssh 기능을 이용할 수 있다.
https://velog.io/@zayson/Jenkins-CICD-3.-Jar-파일을-클라우드-서버로-전달하기
젠킨스 대시보드 > 시스템 설정 > Publish Over SSH 탭으로 이동한다.
Key 텍스트 필드에 클라우드에 접속하는데 사용하는 Private Key를 복사해서 붙여넣어준다.
그리고 하단의 SSH Servers 추가 버튼을 클릭해 내용을 작성해준다.
우선, pull 및 react build가 잘 되는지 확인해 보았다.
pipeline {
agent any
environment {
GIT_URL = "http://172.16.211.84:9090/root/saproject-jm"
}
tools {
nodejs "nodejs-jm"
}
stages {
stage('Pull') {
steps {
git url: "${GIT_URL}", branch: "main", poll: true, changelog: true
}
}
stage('React Build') {
steps {
sh 'npm install -g yarn'
sh 'yarn --cwd ./client install --network-timeout 100000'
sh 'yarn --cwd ./client build'
}
}
}
}
위와 같이 잘 빌드 되는 것을 볼 수 있다,
SSH 설정을 통해 클라우드 서버에 연결이 되었기 때문에 Pipeline Script를 이용해서 젠킨스 서버 경로에 있는 리액트 파일을 클라우드 서버로 전달해줘야한다.
대시보드 > “설정한 파이프라인" > 하단의 Pipeline Syntax를 이용해서 스크립트를 만들어준다.
Snippet Generator의 Steps에서 sshPublisher: Send build artifacts over SSH를 선택한다.
작성한 후 Generate를 통해 pipeline script를 복사한 후 새로운 스테이지를 만들고 steps에 붙여넣었다.
pipeline {
agent any
environment {
GIT_URL = "http://172.16.211.84:9090/root/saproject-jm"
}
tools {
nodejs "nodejs-jm"
}
stages {
stage('Pull') {
steps {
git url: "${GIT_URL}", branch: "main", poll: true, changelog: true
}
}
stage('React Build') {
steps {
sh 'npm install -g yarn'
sh 'yarn --cwd ./client install --network-timeout 100000'
sh 'yarn --cwd ./client build'
}
}
stage('Jenkins to OracleCloud Send Build') {
steps {
sshPublisher(
publishers: [
sshPublisherDesc(configName: 'oracle',
transfers: [
sshTransfer(cleanRemote: false,
excludes: '',
execCommand: 'sh /home/ubuntu/react/script/start_server.sh',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '/react',
remoteDirectorySDF: false,
removePrefix: '',
sourceFiles: 'build/**'
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false)])
}
}
}
}
작성 이후 빌드시 성공적으로 프로젝트 빌드 후 오라클 클라우드로 파일이 넘어가는 것을 확인 할 수 있었다!
https://velog.io/@yoonlang/Jenkins-Git-Webhook-Docker-Nginx-React배포-자동화
https://hello-bryan.tistory.com/169
(Oracle에서 실행)
Dockerfile
# nginx 이미지를 사용합니다. 뒤에 tag가 없으면 latest 를 사용합니다.
FROM nginx
# root 에 app 폴더를 생성
RUN mkdir /app
# work dir 고정
WORKDIR /app
# work dir 에 build 폴더 생성 /app/build
RUN mkdir ./build
# host pc의 현재경로의 build 폴더를 workdir 의 build 폴더로 복사
ADD ./build ./build
# nginx 의 default.conf 를 삭제
RUN rm /etc/nginx/conf.d/default.conf
# host pc 의 nginx.conf 를 아래 경로에 복사
COPY ./nginx.conf /etc/nginx/conf.d
# 80 포트 오픈
EXPOSE 80
# container 실행 시 자동으로 실행할 command. nginx 시작함
CMD ["nginx", "-g", "daemon off;"]
nginx.conf
server {
listen 80;
location / {
root /app/build;
index index.html;
try_files $uri $uri/ /index.html;
}
}
docker build -t nginx-react:0.1 .
$ docker run -d --name my-react-app -p 8300:80 nginx-react:0.1
# host pc 에서 8300 포트로 접속하면 container 의 80 포트로 포워딩.
# -d 는 백그라운드 실행
잘 만들어졌나 container 목록 확인.
docker ps -a
위 일련의 과정을 실행해줄 스크립트를 작성했다.
#!/bin/bash
# 원하는 스크립트 내용
echo "Script Started!"
# 동작중인 컨테이너 정지
docker stop my-react-app
# 컨테이너 삭제
docker rm my-react-app
# 이미지 삭제
docker rmi -f nginx-react:0.1
#Docker image 생성
docker build -t nginx-react:0.1 /home/ubuntu/react/
#Docker Container 실행
docker run -d --name my-react-app -p 8300:80 nginx-react:0.1
# local build file 삭제
sudo rm -rf ../build/*
리액트 파일을 변경 후 commit, push
Gitlab에 Push 확인
Jenkins에서 pull, build, oracle send 확인
nginx 서버에 접속하여 변화 확인
역시나, 이론도 실습을 해봐야 제대로 알 수 있다. 이번에도 그냥 배울때는 CI CD가 뭔지 납득은 되는데 이해도 안되고 하나도 와닿지 않아 어떻게 써야하는지 막막했다. 그러나 한번 부딛혀 보며 직접 구현을 해보니 이해도가 크게 상승했다. 무엇보다, 재미가 생겼다.
처음에는 대충 느낌만 나게 해보자는 생각이었는데 직접 구현하고자 관심을 갖고 공부를 하자 흥미도 생기고 앞으로 내 프로젝트에 어떻게 적용시켜나갈 수 있을지 고민도 해보는 시간이 되었다.
CD를 구현하며 도커에 대한 이해도가 높아져 리액트 빌드파일을 어떤 서버에던지 올릴 수 있게 되어 나만의 서비스를 풀스택으로 만들어 배포하고자 하는 마음이 생겼다.
gitlab에서 branch가 main인데 jenkins에서 동일하지 않아 발생한 듯 함.
jenkins에서 branches를 main으로 바꿔주었다.
(해결 error → 403 error → 200)
우선, 현재 ip주소가 틀렸다.
제대로 된 ip주소로 바꿔주었다
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password). fatal: Could not read from remote repository.
시도 1 : public key 등록 → 여전히 안됨
시도 2 : HTTP로 변경 → 성공! 다만 도커로 포트번호를 직접 적어줘야 한다.