본격적으로 개선된 과정을 기록하기전에 이전 인프라의 특징과 문제점을 다시 한번 알아보겠다.
비교적 간단한 구조로 배포 프로세스를 구축할 수 있다는 장점이 있으며 실제로 아주 간편하게 배포를 마쳤다.
그러나 이 구조의 문제점을 살펴보자면 다음과 같다.
초기 아키텍처처럼 단일 단계에서 모든 작업을 처리하는 방식은 실패시 전체 프로세스가 중단될 수 있는 치명적인 문제점이 있다.
단일 단계에서 모든 작업을 처리하는 방식은 장애 복구 및 롤백이 어려울 수 있다는 단점이 있다. 예를 들어 이미지 빌드 단계에서 문제가 발생하면 롤백하기 위해 이미지를 다시 빌드하고 실행해야하는데 이는 시간과 비용을 소모하고 장애 복구 시간을 늘릴 수 있다.
장애 복구 시간은 예민한 사안이다. 시스템 엔지니어로 일할 적에 장애가 발생하면 고객들은 가장 먼저 '복구 시간이 얼마나 걸리나요?', '복구되는데 오래걸리나요?' 와 같은 질문을 했고 그만큼 빠른 정상화를 요구했었다.
칸반서버는 AWS EC2의 프리티어 스펙에서 돌아가고있다. 1코어 1G 스펙에서 테스트를 하면서 과부하가 오는 순간이 종종 있었다. 특히 이미지를 빌드하면서 먹통 현상이 심했는데 그때마다 재부팅을 해줘야하는게 정말 귀찮고 짜증났다.
물론 실제 서비스를 프리티어 스펙에 올리는 경우는 없겠지만 만일 이 서비스가 단일 컨테이너가 아닌 확장이 필요한 중요한 때에 부하가 발생할 수 있지않을까?
이러한 단점들과 앞서 1탄에서 작성한 도커의 장점을 고려하여 결국 인프라를 개선하게 된 결정적인 원인이 되었다.
앤서블을 도입하고 도커 허브를 사용하여 이미지 빌드 및 실행을 처리하는 서버를 분산시키고 각 서버에 부여되는 작업 부하를 줄이고 안정성을 향상시켰다.
우선 젠킨스를 도커 이미지로 사용하는 이유과 동일하게 앤서블을 컨테이너로 올리고 싶었다.
그러나 젠킨스와 다르게 앤서블은 공식적으로 도커 이미지가 존재하지 않는 것으로 보여져 이전에 CI/CD 강의를 들을 때 사용했던 DockerFile을 활용하기로 했다.
docker run --privileged -itd --name ansible-server -p 10022:22 --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw -e container=docker ansible/ansible /usr/sbin/init
앤서블 플레이북 파일을 이미지 빌드와 컨테이너 실행으로 분리하여 생성해주었다. 이는 작업의 목적과 역할을 명확하게 유지하고 한가지 기능에 집중할 수 있기 위함이다.
create-kanban-image-playbook.yml
- hosts: all
# become: true
tasks:
- name: create a kanban-server docker image
command: /usr/local/bin/docker-compose --env-file /root/.development.env build
args:
chdir: /root
- name: push the image on Docker Hub
command: docker push haeseung/kanban-server
- name: remove the docker image from the ansible server
command: docker rmi haeseung/kanban-server
ignore_errors: yes
- push the image on Docker Hub 확인
create_kanban-continer-playbook.yml
- hosts: all
# become: true
tasks:
- name: stop current running container
command: docker stop api
ignore_errors: yes
- name: remove stopped cotainer
command: docker rm api
ignore_errors: yes
- name: remove current docker image
command: docker rmi haeseung/kanban-server
ignore_errors: yes
- name: pull the newest docker image from Docker Hub
command: docker pull haeseung/kanban-server
- name: create a container using kanban-server-image
command: /usr/bin/docker run -p 3000:3000 --name api --env-file /root/.development.env haeseung/kanban-server
args:
chdir: /root
- create a container using kanban-server-image 확인
이제 젠킨스 파이프라인을 생성하는 것으로 CI/CD 파이프라인을 완성해보자.
pipeline {
agent any
stages {
stage('git clone') {
steps {
git branch: 'develop', credentialsId: '...', url: 'https://github.com/haeseung123/kanbanBoard.git';
}
}
stage('image build & push') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: 'ansible-server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '/usr/local/bin/ansible-playbook -i /root/hosts /root/create-kanban-image-playbook.yml --limit 172.17.0.3', execTimeout: 120000, ...)
}
}
stage('deploy') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: 'ansible-server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '/usr/local/bin/ansible-playbook -i /root/hosts /root/create-kanban-container-playbook.yml --limit 172.31.5.139', execTimeout: 120000, ...)
}
}
}
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"
}
}
}
젠킨스 파이프라인은 프로젝트 생성 시 Pipeline Syntax을 통해 간단하게 생성할 수 있다.
위의 과정을 파이프라인을 통해 하나의 스크립트 파일로 흐름을 제어할 수 있다는 장점이 있으며 아래처럼 모니터링이 가능하기 때문에 넘 조아용~! 어떤 과정을 진행중이고 얼마만큼의 시간이 걸렸는지 확인할 수 있다.
또한 post에 후속 조건을 정의하여 파이프라인의 실행 상태를 확인하고 관련된 조치를 취할 수 있도록 했다.
- 배포 결과
API 서버만 배포한 것이기 때문에 기본적인 메인 화면이 없지만 이 화면으로 서버가 동작하는 것을 확인할 수 있다.
최종적으로 완료된 서비스 아키텍처이다. 위의 과정들을 거쳐 간단하게 서비스를 관리하고 배포할 수 있다.
다만 아쉬운 점은 공부를 하면서 알게된 도커와 젠킨스, 앤서블의 장점들을 전적으로 활용해보지 못한 것이다. 기회가 된다면 ECS를 활용해서 서버를 유연하게 확장/축소하고 오토스케일링까지 도입하여 개선해보려고 한다.