Contents
00. Intro
00-01. CI/CD란?

CI(Continous Integration)
- 지속적인 통합을 의미한다.
- 코드 변경사항이 자동으로 빌드 및 테스트 되어 하나의 레포지토리로 통합되어 관리될 수 있는 것을 의미한다.
CD(Continuous Delivery)
- 지속적인 서비스 제공을 의미한다.
- 개발자들이 적용한 변경 사항이 테스트를 거쳐 레파지토리에 업로드 되는 것이 자동으로 이루어진다.
CD(Continuous Deployment)
- 지속적 배포를 의미한다.
- 고객이 사용가능한 프로덕션 환경까지 자동으로 릴리즈 한다.
- Continuous Delivery와의 차이는 프로덕션 배포까지 자동화 하는가의 차이이다.
00-02. CI/CD 도구
Jenkins
- 무료 오픈 소스이다.
- 플러그인이 많고 커스터마이징을 다양하게 할 수 있다.
- 많은 사용자를 가지고 있기 때문에 관련 문서가 다양하다.
GitLab
- Private repository를 무료로 사용 가능하다.
- 프로젝트 당 repository 저장공간을 많이 허용한다.
- 자체적으로 지원하는 CI 서비스가 있다.
00-03. CI/CD Work Flow

01.사전 작업
- Node.js 설치
- MySQL 설치
- Node.js app 생성
- docker image로 생성 후 docker hub에 push
public docker image 참고 : kicoskillup/node-app:v0.1
02. Kubernetes 환경 구성
Kubernetes 설치
- Master node, Worker node 공통
# sudo hostnamectl set-hostname devops-master
# sudo apt update
# sudo apt upgrade -y
# sudo swapoff -a
# sudo apt install ntp -y
# sudo service ntp restart
# sudo ntpq -p
# sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common gnupg2
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key --keyring /etc/apt/trusted.gpg.d/docker.gpg add -
# sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# sudo apt-get update && sudo apt-get install -y containerd.io=1.2.13-2 docker-ce=5:19.03.11~3-0~ubuntu-$(lsb_release -cs) docker-ce-cli=5:19.03.11~3-0~ubuntu-$(lsb_release -cs)
# sudo mkdir /etc/docker
# cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
# sudo mkdir -p /etc/systemd/system/docker.service.d
# sudo systemctl daemon-reload
# sudo systemctl restart docker
# sudo systemctl enable docker
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
# cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
# sudo apt-get update
# sudo apt-get install -y kubelet kubeadm kubectl
# sudo apt-mark hold kubelet kubeadm kubectl
- Master node
# sudo kubeadm init --apiserver-advertise-address <ip 주소> --pod-network-cidr=<포드 네트워크 IP 주소 범위>
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
- Worker node
[Master에서 생성 된 join Hash Key로 Master에 조인]
# kubeadm join 10.0.1.43:6443 --token qf1bao.ioqs0kckwchqmb66 \
--discovery-token-ca-cert-hash sha256:16704ccc8d93859ef1012e4f532230982c03ede8e7b510b726f73a07f57fa5ff
- Master node
[Network plugin 설치]
# wget https://docs.projectcalico.org/manifests/calico.yaml
# sed -i -e 's?192.168.0.0/16?10.0.1.0/24?g' calico.yaml
# kubectl apply -f calico.yaml
- node 확인

03. Jenkins 설치
구성
- EC2 (ubuntu 18.04)
- Security Group : Allow 22, 8080
Jenkins 설치
- EC2에 Jenknins 설치
[Open JDK 8 설치]
# sudo apt-get update
# sudo apt-get install openjdk-8-jdk
[Jenkins 리포지토리 키 다운]
rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
[apt 데이터베이스에 공식 젠킨스 리포지토리 추가]
# sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > \
/etc/apt/sources.list.d/jenkins.list'
# apt-get update
# apt-get install -y jenkins
[만약 포트 번호 변경 원할 시]
vi /etc/default/jenkins
# port for HTTP connector
HTTP_PORT=8080 <- 8080포트를 원하는 포트로 변경
[Jenkins 실행 및 상태 확인]
# systemctl start jenkins
# systenctl status jenkins
[Jenkins 초기 설정을 위헤 패스워드 가져오기]
# cat /var/lib/jenkins/secrets/initialAdminPassword
[브라우저로 Jenkins 접속]
초기 설정
- 위에서 불러온 AdminPassword 입력

- Plugin 설치

- User 생성


04. GitLab 설치
구성
- EC2 (ubuntu 18.04)
- Security Group : Allow 22, 8001
GitLab 설치
[시스템 업데이트]
# apt update
# apt upgrade -y
[gitlab ce 레파지토리 추가]
# curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
[gitlab 설치]
# apt install -y gitlab-ce

Port 변경
- externer url 포트는 80, 8080을 피하는 것이 좋다.
- gitlab_worhorse & puma는 80, 8080을 피하고 반드시 externer url 포트와 달라야한다.
[port 변경]
# vi /etc/gitlab/gitlab.rb
<gitlab.rb 내용 수정>
external_url '<IP 또는 url:port1>'
gitlab_workhorse['auth_backend'] = "http://localhost:<port2>"
puma['enable'] = true
puma['port'] = <port2>
[gitlab-ctl 설정 적용]
# gitlab-ctl reconfigure
초기 설정
- 초기 비밀번호 확인
# cat /etc/gitlab/initial_root_password | grep Pass
- root 계정으로 로그인

- 로그인 후 비밀번호 재설정
- user 생성

- User로 로그인 후 비밀번호 재설정
05. GitLab Connection 설정
Jenkins에서 ssh 키 생성, public 키 확인
# ssh-keygen
# cat ~/.ssh/id_rsa.pu
=> ssh-rsa @#$!#% 출력
GitLab에서 SSH Keys 등록

프로젝트 연동을 위해 GitLab에서 프로젝트 생성



Jenkins Plugin
- Jenkins에서 연동을 위해 필요한 Plugin 추가
- git plugin, gitlab plugin



Jenkins Creditials 추가
- Jenkins에서 GitLab에 대한 Creditials 추가
- Dashboard > Jenkins 관리 > Manage Creditials


GitLab에서 Access token 생성


- access token은 다시 확인할 수 없으므로 따로 복사해둔다.
GitLab Connection 설정
- Jenkins 시스템 설정에서 GitLab connection 설정


- API tocken 부분에 GitLab에서 받은 Access token 입력

- Credentials 적용 후 Test Connection 시도

06. Webhook을 이용한 Build Triggers 설정

Webhook Plugin 추가

Jenkins Pipeline 생성
- 새로운 Item 생성
- Dashboard > 새로운 Item > pipeline

- Build Triggers 설정


GitLab에서 Webhook 설정
- Project > Settings > Webhook
- URL은 Jenkins Build Triggers의 ①번 URL
- Secret token은 Jenkins Build Triggers의 ④번 Secret token

- Push events Test


- Test 후 Jenkins에 Build 되는 것 확인한다.

07. Jenkinsfile을 이용한 pipeline
07-01. Docker hub와 연결하는 pipeline

Jenkins pipeline 구성
- ① Definition : GitLab에서 코드를 관리 하고자 하면 ‘Pipeline script from SCM’ 선택, Jenkins에서 직접 script를 작성하고자 할 때는 ‘pipelins script’를 선택하면 된다.
- ② Repository URL : 코드 관리를 할 자신의 GibLab URL
- ③Credentials : 앞서 생성한 GitLab용 Credential 선택
- ④Branch Specifier: Jenkinsfile이 있는 origin branch 입력
- ⑤Sscipt Path: 자신의 Jenkinsfile 이름 입력 (ex. Jenkinsfile or Jenkinsfile.groovy)

Docker Hub 연결을 위한 Credential 생성

Docker Plugin 추가
- docker image build, push를 위해 docker 관련 plugin을 추가한다.

Jenkins Server에 docker 설치
# sudo apt-get update
# sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# apt-get update
# sudo apt-get install -y docker-ce docker-ce-cli containerd.io
GitLab에 Jenkinsfile 추가
- Jenkins.groovy
node {
stage('Clone repository') {
checkout scm
}
stage('Build image') {
app = docker.build("<dockerhub id>/node-server:$BUILD_NUMBER")
}
stage('Push image') {
docker.withRegistry('https://registry.hub.docker.com', 'dockerhub') {
app.push("${env.BUILD_NUMBER}")
}
}
}
Build 확인
- login 접속 오류 시 docker.sock 변경
# chmod 666 /var/run/docker.sock


07-02. Kubernetes와 연결하는 pipeline

Jenkins에 Kubernetes 설치
# sudo apt-get update
# sudo apt-get install -y apt-transport-https ca-certificates curl
# sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
# echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
# sudo apt-get update
# sudo apt-get install -y kubectl
Jenkins에 kubernetes Plugin 추가

Kubernetes Credentials 생성
- Kubernetes master node (.kube/config)
[config파일 보는 법]
# cat /root/.kube/config

- Credential 생성

- Jenkinsfile.groovy 추가 변경
node {
stage('Clone repository') {
checkout scm
}
stage('Build image') {
app = docker.build("dmswjd9997/node-server:$BUILD_NUMBER")
}
stage('Push image') {
docker.withRegistry('https://registry.hub.docker.com', 'dockerhub') {
app.push("${env.BUILD_NUMBER}")
}
}
stage('Kubernetes deploy') {
steps {
kubernetesDeploy configs: "deployment.yaml", kubeconfigId: 'kube'
sh "kubectl --kubeconfig=/root/.jenkins/.kube/config rollout restart deployment/node-deployment"
}
}
}
