본문 바로가기
개발공부 개발새발/CICD

CI/CD ) Ansible 로 배포 자동화하기 !

by 휴일이 2024. 5. 14.

Ansible 을 사용해서 컨테이너 만들기

  • 젠킨스가 github 에서 코드를 갖고 온다.
  • 아티팩트를 만들어서 Ansable Server 에 복사한다.
  • Ansible 이 docker 로 이미지를 만들어 docker hub 에 푸쉬한다.
  • 배포할 때는 docker 가 dockerhub 에서 이미지를 당겨와서 사용한다.
  • docker host 를 ansible 로 관리한다.

Ansible 서버 준비하기

EC2 인스턴스 생성 후 hostname 변경

sudo su -
vi /etc/hostname

---
# 호스트 이름 변경 후
---

# 시스템 재시작
init 6

ansible 용 유저 추가

sudo su -

# user 추가
useradd ansadmin
passwd ansadmin

---
# 패스워드 추가 작업
---

# visudo 에서 권한 변경
visudo

## Allows people in group wheel to run all commands
# %wheel        ALL=(ALL)       ALL
ansadmin ALL=(ALL)	  ALL

# ansadmin 이 암호 없이 명령 실행 가능하도록 변경
vi /etc/ssh/sshd_config

PasswordAuthentication yes
# PermitEmptyPasswords no

# reload
service sshd reload

ssh-key 만들기

sudo su - ansadmin

# 이 명령어로 ssh key 를 만들어준다. 참고로 경로 다 기본경로로 할거면 계속 엔터만 하면 됨.
ssh-keygen

Ansible 설치

sudo su -

yum install ansible

ansible --version

dockerhost 를 Ansible 에 추가

앤서블 서버가 docker 를 관리할 수 있도록 설정을 해주자.

docker 서버에 유저 추가

sudo su -

useradd ansadmin
passwd ansadmin

권한 변경

visudo 

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL
ansadmin ALL=(ALL)	 NOPASSWD: ALL

# 암호 인증 활성화 여부 확인
# 만약 활성화되어있지않으면
# vi /etc/ssh/sshd_config 해서 수정하면 됨.
grep Password /etc/ssh/sshd_config

ansible 서버에 docker host 추가

vi /etc/ansible/hosts

# 해당 파일에 내용이 있다면 전부 다 지운 후,
# 해당 파일이 없다면 새 파일을 추가한다.
# 파일 내용은 dockerhost 의 privateIP 를 적어주면 된다.

예) (없는 IP 쓴 것임, 이렇게 달랑 쓰기만 하면 됨)
176.144.12.1

관리자 key 복사

sudo su - ansadmin

# 아까 만들었던 ansadmin 용 ssh key 를 docker host 로 보낸다.
ssh-copy-id (dockerhostPrivateIP)

확인 작업

# in ansible-server
sudo su - ansadmin

ansible all -m ping

ansible all -m command -a uptime

# in docker-host
sudo su - ansadmin

uptime
  • 둘의 uptime 은 같을 것이다. 그러면 서로 잘 통신하고 있다는 것을 확인 가능 :)

Ansible with Jenkins

때가 왔다. 앤서블과 젠킨스를 통합해주자.

jenkins 에 ansible-server 설정

  • ansible 서버 설정을 해준다.
  • Hostname 에는 ansible 의 privateIP 를 적으면 되고, Password 에는 ansadmin 의 비밀번호를 적으면 됨.

새 작업 생성

  • 기존 작업을 카피해서 새 아이템을 생성해준당.

  • 기존 SSH-Server 를 ansible-server 로 변경한다.
  • Exec command 는 삭제해준다.
  • Remote directory 경로는 ansible 서버에는 존재하지 않기 때문에, 만들어줘야한다.
cd /opt

sudo mkdir docker

# docker 디렉토리의 권한을 ansadmin 으로 바꿔줘야한다.
# 그래야 ansadmin 호스트에서 접근 가능.
sudo chown ansadmin:ansadmin docker
  • 설정 완료 후 정상 빌드됐을 때, ansible-server 에서 확인해보자.
cd /opt/docker

ll

# ll 했을 때 이렇게 webapp.war 파일이 존재한다면 빌드가 성공적이었음을 확인할 수 있다 :)
-rw-rw-r--. 1 ansadmin ansadmin 2540 May 14 01:44 webapp.war

Ansible 로 도커 이미지를 빌드하고 컨테이너 만들기

도커 설치

# in ansible-server

sudo yum install docker

# 이제 ansadmin 을 여기서 보이는 docker group 에 추가해서 명령어를 사용하게 해줄 것임.
cat /etc/group

# ansadmin 을 docker 그룹에 추가
sudo usermod -aG docker ansadmin

# 여기에서 도커 그룹에 속해있다고 뜬다면 성공적으로 그룹에 넣은 것.
id ansadmin

# 도커 시작
sudo service docker start

도커파일 작성

cd /opt/docker

vi Dockerfile

---
# docker-host 에서 작성했던 도커파일을 그대로 복붙.
FROM tomcat:latest
RUN cp -R /usr/local/tomcat/webapps.dist/* /usr/local/tomcat/webapps
COPY ./*.war /usr/local/tomcat/webapps
---

# 하면 권한이 없다고 빌드가 안 됨.
# 권한을 줘야 가능.
docker build -t regapp:v1 .

# 앞에 sudo 를 붙여서 관리자 권한으로 실행할 수도 있지만 매번 실행할 때마다 sudo 를 추가해줘야해서 귀찮으니
# 도커에 읽기 전용 권한을 줘서 빌드를 가능하도록 두자.
sudo chmod 777 /var/run/docker.sock

# 다시 빌드하면 잘 됨.
docker build -t regapp:v1 .

# 컨테이너 실행, -t 해서 컨테이너에 접속해보면 무리없이 잘 동작하는 걸 확인 가능 '-'
docker run -t --name regapp-server -p 8081:8080 regapp:v1

  • ansibleServerPublicIP:8081 로 접속하면 실행되고 있는 톰캣 컨테이너를 확인 가능

Ansible Playbook 만들기

  • 출처 : redHat
  • 자동화를 담당하는 기술이다.(인 것 같다..)
  • playbook을 만들어 이미지를 만들어 도커 허브에 푸쉬하고 배포하는 작업을 자동화해보자 😊

ansible 호스트 서버 추가

ansible 에서 접속할 수 있도록 서버를 추가해줘야 함. (본인 ip 도 추가해줘야 한다.)

sudo vi /etc/ansible/hosts

---
[dockerhost]
172.11.5.15

# ansible 서버를 추가해준다. private IP 를 사용하면 됨.
[ansible]
172.12.30.1
---

# ansible 과는 통신이 안 될 것이다. (FAILED)
# dockerhost 를 사용할 때 했듯이 ssh key 를 만들어 추가해줘야 
ansible all -a uptime

# ansible 서버 ssh key 가져오기
ssh-copy-id 172.12.30.1
# 사실 이것도 되긴 한다. 어쨌든 ansible 로컬에서 실행하는 거니까.
ssh-copy-id localhost

# 다시 실행하면 전부 신호가 갑니다.
ansible all -a uptime

regapp.yml

  • playbook을 만들기 위한 설정 파일을 작성해준다.
cd /opt/docker
vi regapp.yml

# regapp.yml (---부터 시작이다. --- 추가해줘야함.)
---
# all 로 모든 호스트를 추가해줘도 되지만, ansible 호스트가 할 행동임을 명시하자.
- hosts: ansible
  
  tasks:
	  # 작업 제목
  - name: create docker image
	  # 리눅스 명령으로 shell 실행
    command: docker build -t regapp:latest .
    args:
	    # /opt/docker 아래에 명령을 실행하겠다는 얘기.
      chdir: /opt/docker

플레이북 생성 후 이미지 자동 빌드

# check 하면 성공 실패 문법실패여부 확인 가능
ansible-playbook regapp.yml --check

# check 하고 이상 없으면 플레이북 실행!
ansible-playbook regapp.yml

# 이미지가 생성된 것 확인하기
docker images

Ansible 아 Docker container 를 만들어줘

push image to docker hub

  • 도커허브에 가입된 아이디가 있어야 한다.
# in ansible-server
docker login
# 내 도커허브 아이디/비번으로 로그인해줌

# 태그를 변경해줌. 접두사로 내 도커허브 아이디를 적어줘야 도커허브에 푸쉬 가능.
docker tag IMAGE_ID holidaykang/regapp:latest

docker push holidaykang/regapp:latest

  • 레포가 자동으로 생성된당.

update regapp.yml

---
- hosts: ansible

  tasks:
  - name: create docker image
    command: docker build -t regapp:latest .
    args:
      chdir: /opt/docker

  - name: create tag to push image to dockerhub
    command: docker tag regapp:latest holidaykang/regapp:latest

  - name: push docker image
    command: docker push holidaykang/regapp:latest
  • push image to dockerhub 과정을 yml 파일에 담기 위해 기존 파일을 수정해준다.
ansible-playbook regapp.yml --check

# 이제까지는 ansible group 에게 전부 하는 행동이었지만
# 그룹 중에서도 IP 한정으로 할 수도 있다.
# 근데 어차피 지금은 /etc/ansible/hosts 에 [ansible] 그룹에 ip 하나밖에 없음.
# 이렇게 명시 안 해도 상관 없다.
ansible-playbook regapp.yml --limit 172.12.3.91

Jenkins 에게 ansible-playbook 명령 대신 실행하게 하기

  • jenkins 에서 Exec command 에 해당 명령을 실행하게 한다.
    • ansible-playbook /opt/docker/regapp.yml

  • 그리고 업데이트 1분마다 확인해서 pull 해오도록 설정을 변경해주자.

deploy_regapp.yml

  • vi deploy_regapp.yml
---
- hosts: dockerhost

  tasks:
  - name: create container
    command: docker run -d --name regapp-server -p 8082:8080 holidaykang/regapp:latest
  • 컨테이너를 만드는 명령을 하도록 설정 파일을 추가한다.
  • 이미지를 당겨와서 컨테이너를 만드는 건 dockerhost 호스트가 처리하도록 설정했다.

ansible 에서 yml 파일을 playbook 으로 만들기

ansible-playbook deploy_regapp.yml --check

# check 실행 후 문제없으면 실행
ansible-playbook deploy_regapp.yml

# 만약 --check 할 땐 문제없었는데 실제로 실행할 때 문제가 있고 permission denied 오류가 뜬다면
# 해당 명령어를 dockerhost 서버에서 실행해주자.(읽기 권한 허용)
chmod 777 /var/run/docker.sock
# 이러고 다시 실행하면 성공함.
ansible-playbook deploy_regapp.yml

  • dockerhost 용 publicIP 로 접속해보면 변경사항이 그대로 반영된 것을 확인 가능..

문제

ansible-playbook deploy_regapp.yml
  • 다시 이 명령을 하면 실패한다.
    • 이미 같은 이름의 컨테이너가 있다는 오류.
  • 이 오류를 해결해줘야 함. → 컨테이너를 만들기 전 기존 컨테이너와 이미지를 지워야겠죠?

update deploy_regapp.yml

  • 기존 컨테이너와 이미지를 지우는 명령을 추가하자.
---
- hosts: dockerhost

  tasks:
  - name: stop existing container
    command: docker stop regapp-server
    ignore_errors: yes

  - name: remove the container
    command: docker rm regapp-server
    ignore_errors: yes

  - name: remove image
    command: docker rmi holidaykang/regapp:latest
    ignore_errors: yes

  - name: create container
    command: docker run -d --name regapp-server -p 8082:8080 holidaykang/regapp:latest
  • ignore_errors: yes 는 해당 명령을 입력했을 때 에러가 뜨더라도 스킵시키는 설정이다.
  • 이미지나 컨테이너가 존재하지 않을 경우 해당 명령이 에러를 일으켜 playbook 실행이 중단되지만, 해당 설정을 해두면 이미지나 컨테이너가 없어 해당 구간에 오류가 일어나더라도 스킵한다 😊

deploy_regapp.yml 실행

ansible-playbook deploy_regapp.yml --check

ansible-playbook deploy_regapp.yml
  • 정상 실행되는 것을 확인 가능.

docker image module - ansible

community.docker.docker_image module – Manage docker images — Ansible Community Documentation

  • 해당 사이트에 들어가면 설명과 예시가 있다.

마지막 : 위의 과정 전부 자동화하기

이제 자동화의 시간이다.

jenkins 설정 추가

ansible-playbook /opt/docker/regapp.yml;
sleep 10;
ansible-playbook /opt/docker/deploy_regapp.yml
  • 둘 다 바로 렌더링 할 순 없으니 sleep 10 명령어로 10초 뒤에 다음 명령이 실행되도록 한다.

저장 후 깃에 새 코드를 푸쉬해주면..

  • Email -> Enter Email 로 이름 바뀜
  • docker-host:8082 로 접속해보면 코드 변경사항이 자동으로 적용되는 것을 확인 가능! ^0^/

 

자동화 했으나… 문제점

  • docker container 가 내려가고 올라가는 사이에 서버가 내려감. 그 때 사용자가 서버에 접속할 수 없음..
  • 혹시 도커 컨테이너가 죽으면 복구 방법이 없음.

 

💡 쿠버네티스를 사용하면 해결된다. ^0^/ 다음 포스팅에선 쿠버네티스로 배포하기로!
728x90