본문 바로가기

DevOps

Docker container 를 활용해 CI/CD 실습해보자 feat(Jenkin, Ansible, Minikube)

728x90

DevOps 또한 자동화를 한다거나 코드로 관리할 수 있다면 얼마나 좋을까?

이러한 수요로인해 요즘 각광받고 있는것이 바로 IaC(Infrastructure as Code) 이다.

대표적으로 'ansible' 과 'terraform' 이 있는데, terraform' 의 경우 필요한 라이브러리나 서비스를 설치하는 단계인 프로비저닝에서 많이 사용하고, 자동화를 'ansible' 로 구성하는 두 가지 IoC 툴을 혼용하는 추세이다. 

 

참고 기사

인프라 관리 자동화, ‘IaC’로 구현한다

 

이번 실습에서는 docker , jenkins , ansible , kubernetes(minikube활용) 을 사용해 어떤식으로 배포를 할 수 있는지 알아보도록 하자.

 

Docker 를 활용하면 virtualBox 를 활용한 것보다 훨씬 간단하게 로컬에서 CI/CD 환경을 구성해 볼 수 있는 장점이 있다. (필자의 경우 virtualBox 에서 우분투를 설치하는데에만 1시간 넘게 걸렸었다... 그리고 virtualBox 의 GUI 를 활용해 환경을 구성하는 것보다 직접 명령어를 통해 구성하는 것이 더 재밌다!)

먼저 docker 를 활용해 ubuntu 컨테이너를 설치해 서버로 활용할 것이다. 이를 위해 ubuntu 이미지를 다운받아 주자. 


 

  • 호스트 PC
docker search ubuntu
docker pull ubuntu

 

그리고 도커 내부에서 앞으로 설치할 컨테이너간의 통신이 가능하도록 network 그룹을 만들자.


  • 호스트 PC
docker network ls
docker network create kube

 

이제 Ubuntu 컨테이너를 만들어주자.

여기서는 jenkins 서버로 활용할 컨테이너 kube-jenkins ,

ansible 서버로 활용할 컨테이너 kube-ansible ,

kubernetes 서버로 활용할 컨테이너 kube-minikube (minikube 란 가벼운 쿠버네티스 구현체이다.)

이렇게 만들어 줄 것이다.

다음 그림과 같이 Jenkins 를 통해 CI/CD 관리를 할 것이기에 host pc의 localhost 에서 Jenkins 에 접속하기위해 8080 포트를 추가로 포워딩 시켜주었다. 


  • 호스트 PC
docker run -d -i -t --name kube-jenkins -p 10022:22 -p 8080:8080 --net kube ubuntu

 

우선 kube-jenkins 컨테이너에 들어가 기본적인 것들을 설치해준 후 이를 도커 이미지화 시켜 놓을 것이다.


  • 호스트 PC /  kube-jenkins
docker exec -it kube-jenkins bash
apt-get update
apt-get install sudo net-tools vim openssh-server curl

 

ssh 의 경우 다음과 같이 /etc/ssh/sshd_config 설정에 PermitRootLogin yes 를 추가해 줘야 ssh 를 활용한 접속이 가능하다.


  • kube-jenkins
vi /etc/ssh/sshd_config
# -->
# PermitRootLogin without-password
# 아래와 같이 바꾸거나 없으면 추가하자
# PermitRootLogin yes
# --<

 

root 계정에 password 를 추가하고 password 를 사용해 ssh 접속이 가능하도록 해주자.


  • kube-jenkins
passwd root
service ssh start

 

`exit` 로 컨테이너에서 나와서 `ssh root@localhost -p 10022` 로 ssh 접속이 되는지 확인한 후 다시 `exit` 로 나와 현재까지 셋팅한 컨테이너를 이미지로 만들어 ansible 컨테이너를 만드는데 사용하자.


  • 호스트 PC
docker commit kube-jenkins kube-default-ubuntu
docker run -d -i -t --name kube-ansible -p 20022:22 --net kube kube-default-ubuntu

 

이제 kube-jenkins 에 jenkins 를 설치해보자. 최신 jenkins 를 설치하기 위해서는 java 11 버전 이상이 필요하다.

(참고로 gradle 의 경우 jenkins 에서 `Invoke Gradle script` 를 이용하면 따로 설치할 필요 없다. 하지만 혹시라도 설치를 원한다면 `apt-get install gradle` 을 통해 설치하면 된다. )

또한 추가적으로 `apt-get install git` 으로 git 또한 설치해주자


  • 호스트 PC / kube-jenkins
docker exec -it kube-jenkins bash
apt-get install openjdk-11-jdk
curl -fsSL https://pkg.jenkins.io/debian/jenkins.io.key | sudo tee \
    /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
    https://pkg.jenkins.io/debian binary/ | sudo tee \
    /etc/apt/sources.list.d/jenkins.list > /dev/null
apt-get update
apt-get install jenkins
apt-get install git

 

이제 jenkins 를 실행해 주면 비밀번호가 나오는데 이를 복사해서 localhost:8080에 접속해 사용해주자


  • kube-jenkins
jenkins
# ---
# ...
# "b5a03f6534e447a18818bdf0dfb8a8a3"
# ...
# ---

 


install sugested plugins 를 눌러 필요한 기본 plugins 들을 받아주도록 하자.

그 후 계정을 생성해 진행해 주면 된다.

 

이제 ansible 서버를 구성해보자. ansible 은 python 으로 개발되었기에 python 이 설치되어있어야한다.


  • 호스트 PC / kube-ansible
docker exec -u root kube-ansible bash
apt-get update
apt-get install python3
apt-get install python3-pip
pip3 install ansible

 

이제 실습을 위한 간단한 프로젝트가 필요하다. 아래 깃헙에 간단한 프로젝트를 올려놓았다.

간단한 샘플 프로젝트 소스코드

 

GitHub - Hooneats/kube-cicd

Contribute to Hooneats/kube-cicd development by creating an account on GitHub.

github.com

 

jenkins 에서 생성한 Item 에 다음과 같이 설정해 주면 된다.

Add build step 에 Invoke Gradle script 를 선택 후 Use Gradle Wrapper 를 클릭하면 따로 gradle 설치없이 jenkins 가 gradle wrapper 로  Tasks 를 실행해 준다. Make gradlew executable 를 체크하면 권한문제로 실행이 되지 않는 문제를 방지할 수 있다.

 

Execute shell 에 다음을 추가해 잘 완료 되었는지 확인해 보자.

 

이제 저장 후 빌드를 하면 다음과 같은 console 결과를 볼 수 있다.

 

이제 gradle 통해 생성된 jar 파일을 도커가 설치되어있는 다른 서버에 이동시켜보자 그러기 위해 먼저 jenkins plugin 에 추가적인 Publish Over Ssh 를 설치하자.

 

 

이제 jenkins 관리 -> Configure System 에 들어가 kube-master 와 연결해볼 것이다.

Publish over SSH 항목에 `추가` 버튼을 눌러 다음과 같이 알맞은 정보를 입력해주자.

 

보통은 jenkins 서버에서 `ssh-keygen -t rsa -C "test" -m PEM` 을 활용해 private key 와 public kye 를 만들고,

이 경우 private key(id_rsa) 를 아래 이미지의 Key 항목에 넣어주고, public key(id_rsa_pub) 내용을 kube-ansible 등(접속할 서버) 서버에 /root/.ssh/authorized_keys 안에 넣어줘야한다.(ssh-copy-id root@[접속할 서버] 로 넣어줄 수도 있다.)

참고 블로그1  /  참고 블로그2

 

하지만 여기서는 간단하게 위에서 설정한 Password 를 활용해 연결해보자. 

참고로 SSH Server 에 Hostname 은 `docker network inspect [네트워크 이름]' 명령어로 확인할 수 있다.


  • 호스트 PC
docker network inspect kube

 

그 후 item 구성에 들어와 빌드 후 조치에 `Send build artifacts over SSH` 를 추가 아래의 이미지 처럼 작성해 준다.

여기서 중요한것은 Source files 의 경로는 workspace 상대경로로 적어야한다.

 

Add Transfer Set 을 눌러 Dockerfile 또한 같이 kube-master 서버로 전송해주자

 

 

이제 kube-minikube 서버를 만들어보자. docker 를 통해 minikube 를 설치할 것이다. 이를 위해서

Docker in Docker 가 필요하고 우리는 현재 PC 인 호스트 PC 와는 별개로 작동하는 Docker 인 Real Docker in Docker 로 사용할 것이다.

Docker in Docker 에 대해 : 참고 블로그1 , 참고 블로그2 , 참고 블로그3

minikube 설치 :  참고 블로그1 , 참고 블로그2

 


  • 호스트 PC / kube-minikube
docker run --privileged -d --name kube-minikube --net kube -p 30022:22 -p 9090:8080 docker:dind
apk update
apk add curl
apk add sudo
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \
      && chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/
minikube version
minikube start --force --driver=docker
minikube kubectl -- get pods -A
minikube status

 

minikube 도 설치가 되었다면 실제 kubernetes 처럼 kubectl 명령어를 사용하기 위해 kubectl 설치도 진행하자


  • kube-minikube
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
kubectl version --output=json
kubectl get pods

 

kube-minikube 서버에 ssh 또한 설치하자 

우선 service 명령어를 사용할 수 있도록 openrc 를 먼저 받고 sshd 를 받자

ssh 설치 : 참고1 , 참고2 , 참고3


  • kube-minikube
apk add openssh-server
vi  /etc/ssh/sshd_config 
# --> PermitRootLogin 설정을 yes 로 -> PermitRootLogin yes 추가
passwd root
# --> 비밀번호 설정

apk add openrc --no-cache
apk add openssh
rc-update add sshd
rc-status
/etc/init.d/sshd start

 

이제 kube-jenkins 서버 SSH publishers 에 kube-ansible 을 추가했듯이 kube-minikube 를 추가해 주자.

 

 

그리고 kube-ansible 서버에서 kube-minikube 서버에 ping 을 먼저 보내보자.

이를 위해 kube-minikube 에 python 이 설치되어있어야 하기에 kube-minikube 서버에 python 을 설치하자


  • kube-minikube
apk add python3

 

또한 kube-ansible 이 kube-minikube 서버에 접속이 가능하도록,  kube-ansible 서버에서 ssh 키를 생성해 kube-minikube 서버에 복사해 주자.


  • kube-ansible
ssh-keygen
ssh-copy-id root@172.24.0.2
# --> 172.24.0.2 는 kube-minikube 서버

vi hosts
# -->
# 172.24.0.2
# ---< 추가

ansible all -i ./hosts -m ping

 

다음과 같은 결과를 볼 수 있다.

 

다음으로 Git-hub 에 Dockerfile 을 build 하는 plybook 파일을 만들어보자.

kube-minikube 로 복사되어있는 Dockerfile 을 build 후 image 를 docker-hub 에 push 하는 playbook 파일이다.


  • kube-ansible
- hosts: all

  tasks:
    - name: if exists image then remove
      command: docker rmi hooneats/kube-project
      ignore_errors: yes

    - name: build docker image, name kube-project
      command: docker build -t hooneats/kube-project .
      args:
        chdir: /root

    - name: push docker image
      command: docker push hooneats/kube-project

 

추가적으로 docker-hub 에 push 를 위해 kube-minikube 서버에서 `docker login` 으로 login 해놓자

docker-hub 로그인 : 참고 블로그1


  • kube-minikube
docker login

 

또한 kube-minikube 서버 에 kubernetes 를 사용해 서비스를 구동시킬 파일을 두가지 만들자


  • kube-minikube

kube-mini-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-mini-deployment
spec:
  selector:
    matchLabels:
      app: kube-mini-project
  replicas: 2

  template:
    metadata:
      labels:
        app: kube-mini-project
    spec:
      containers:
        - name: kube-mini-project
          image: hooneats/kube-project
          imagePullPolicy: Always
          ports:
            - containerPort: 8080

  • kube-minikube

kube-mini-service.yml

apiVersion: v1
kind: Service
metadata:
  name: kube-mini-service
  labels:
    app: kube-mini-project
spec:
  selector:
    app: kube-mini-project
  type: NodePort
  ports:
    - port: 8080
      targetPort: 8080
      nodePort: 32000

 

 

추가적으로 kube-minikube 서버에 저장해 놓은 두가지 파일을 실행시킬 playbook 파일 또한 Git-hub 에 추가해 주었다.


kube-minikube-deployment-playbook.yml

- name: Create pods from deployment
  hosts: all

  tasks:
    - name: Delete previous deployment
      command: kubectl delete deployment.apps/kube-mini-deployment

    - name: Create deployment
      command: kubectl apply -f kube-mini-deployment.yml

kube-minikube-service-playbook.yml

- name: Create service
  hosts: all

  tasks:
    - name: create service tasks
      command: kubectl apply -f kube-mini-service.yml

 

 

이제 kube-ansible 에 playbook 파일을 전송하고 playbook 파일을 실행하도록 jenkins 를 구성해보자.

새로운 Item 에서 jenkins-project 로 만들자

 

jenkins-project

 

이제  jenkins-project 가 빌드가 완료되면 ansible 이 실행되도록 ansible-project 도 새로운 item 으로 추가해주자.

 

ansible-project

 

여기까지 진행 후 jenkins-project 를 build 하면 kube-minikube 서버에 다음과 같이 service 가 생성된 것을 볼 수 있다.

 

보통 kubernetes 라면 외부와 연결된 포트인 NodePort 를 통해 서비스에 접속이 가능하지만 minikube 는 자체적으로 외부 IP를 막는지 접속이 되지 않았다... minikube 의 ip 를 사용해 접근해야한다고 하는데... 이를 위해 다음과 같이 kube-minikube 서버에서 입력하면 서비스를 볼 수 있다.

참고 블로그1 

 

-----------------------------------------------------------------------------------

 

추가적으로

kube-minikube 서버를 docker 에 image push 하는 용도로만 사용하고 호스트 PC 에서 docker-desktop 에 kubernetes 설치를 이용해 kubernetes 설치 후 호스트 PC 를 이용할 수도 있다.

혹시라도 필자처럼 window 사용자라면 ssh 서버를 설치해야하기에 다음 블로그를 참고하길 바란다.

window ssh 설치 : 참고 블로그

 

 

728x90