2022. 10. 23. 23:41ㆍCICD
빠른 서비스 제공과 트렌드 반영을 위해 대두되고 있는 DevOps 개념 때문에 CI/CD는 이제 필수가 되었다.
CI/CD는 애플리케이션의 통합 및 테스트 단계에서부터 제공 및 배포에 이르는 애플리케이션의 라이프사이클 전체에 걸쳐 지속적인 자동화와 지속적인 모니터링을 제공하는 것을 의미한다.
이러한 구축 사례를 일반적으로 "CI/CD 파이프라인"이라 부른다.
MSA가 도입되면서 어플리케이션은 많아지고 CI/CD 파이프라인도 증가했다.
또한 Docker, kubernetes 등 컨테이너 기반 배포가 도입되면서 CI/CD 파이프라인은 더욱 복잡해졌고 이것들 역시 관리 포인트가 되었다.
DevOps 개발자라는 직군이 나온 이유가 여기에 있는 듯 하다.
코드양이 많아지면 리팩토링을 통해 공통 모듈들을 도출하고 구조화 하듯 CI/CD 파이프라인도 관리 포인트가 늘어남으로써 리팩토링과 비슷한 과정들이 필요해 졌다.
이 과정들은 코드 리팩토링처럼 개발자에 따라 다르고 기업의 개발문화에 따라 많이 다를 것이다.
이번 포스트에서는 그 중 하나의 과정인 Docker Base Image 파이프라인에 대해 정리해 보겠다.
1. base image에 CI/CD 파이프라인이 필요한 이유
보통 Base Image라 함은 어플리케이션이 돌아갈 OS나 언어 환경으로 만들어진 이미지를 말한다.
Docker Hub에서 필요한 이미지를 검색해 Base Image로 사용하곤 한다.
이렇게 Docker Hub에서 검색한 이미지를 도커 파일에 FROM으로 놓고 어플리케이션에 필요한 작업들을 기술한다.
이후 docker build 명령어를 활용해 커스텀 이미지로 빌드한 후
registry(docker hub, ECR 등)에 푸시하고 이를 배포하여 사용한다.
하지만 프로젝트에서 쓰일 베이스 이미지는 Docker Hub에서 바로 받아오는 형태로 쓰는 것보다 private registry에 올려두고 해당 이미지를 베이스로 사용하는 것이 좋다.
이유는 Docker Hub의 네트워크 문제 등으로 인해 베이스 이미지를 받아오는데 실패할 수 있기 때문이다.
만약 spring 프로젝트의 베이스 이미지를 adoptopenjdk/openjdk11를 쓴다고 하면
보통은 프로젝트 Dockerfile에
FROM adoptopenjdk/openjdk11
CMD ["./mvnw", "clean", "package"]
ARG JAR_FILE_PATH=target/*.jar
COPY ${JAR_FILE_PATH} app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
이런 형태로 기술할 것이다.
하지만 위에서 언급했듯이 맨 위 From 절을 프로젝트에서 가지고 있는 private registry에 올려둔 base 이미지를 사용하는 것이 좋다.
Docker Hub에서 adoptopenjdk/openjdk11 이미지를 pull 받아서
docker tag 명령어를 이용해 이미지 이름을 base-spring-image로 변경하고 ECR에 push 한다.
위 화면처럼 ECR에 base-spring-image가 올라왔다면
프로젝트 dockerfile에서도 FROM 부분에 ECR의 URI 부분을 적어두면 프로젝트 이미지 빌드때도 해당 ECR에 있는 base image를 가져와서 도커 빌드를 수행할 것이다.
하지만 이 방법은 한번의 명령어를 서버에 접속해 수행한 것 뿐이다.
만약 이 작업을 다시 해야한다면 어떨까?
만약 MSA로 구성된 spring 프로젝트 20개 컨테이너에 git이 필요하게 됬다면 어떨까?
모든 프로젝트의 Dockerfile에 git 설치 명령을 넣어서 새로 빌드할 것인가?
좀 더 현실적으로 aws의 로깅 서비스인 cloud watch에서 서버의 health 로그를 수집하려 하면 프로젝트 20개 컨테이너에 해당 agent를 설치해야한다.
앞선 예시처럼 모든 프로젝트 Dockerfile에 설치 명령을 넣어서 빌드해야할까?
이는 매우 비효율적이고 CI/CD 사상에서도 벗어나 있다.
처음부터 Dockerfile 형태로 base image를 정의해두었다면 여기에만 프로젝트 공통으로 해야할 명령을 수행한 후 이미지 빌드를 하면 전체 프로젝트에 적용되게 된다.
2. 구성 예시
아래는 spring 베이스 이미지의 예시이다.
FROM adoptopenjdk/openjdk11
초기에는 프로젝트의 기반이 되는 docker hub의 base image만 만들어 둔다. 파일명은 spring.dockerfile
이를 pipeline-template란 이름의 Git 레포지토리를 만들고 Docker라는 폴더 아래 두고 커밋해 둔다.
pipeline-template
ㄴDocker
ㄴspring.dockerfile
이제 spring 프로젝트의 컨테이너에 공통적으로 필요한 사항은 이 파일을 업데이트하여 처리한다.
만약 AWS Cloud Watch Agent를 설치한다면
FROM adoptopenjdk/openjdk11
RUN curl -O https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
RUN dbkg -i -E ./amazon-cloudwatch-agent.deb
위처럼 cloud watch agent를 다운로드 받아서 실행시키는 명령을 실행한다.
이 폴더 구조는 프로젝트에 만약 빅데이터 컨테이너들이 들어와 python 기반의 베이스 이미지가 필요하다면
python.dockerfile로 만들어두고 같이 관리하면 된다.
3. 젠킨스 설정
젠킨스에 item을 하나 만들고 베이스 이미지 빌드, 푸시과정을 버튼하나로 자동화 해보자
pipeline 으로 도커 베이스 이미지를 컨트롤 할 item을 생성한다.
pipeline{
agent any
parameters{
string(name:"BASE_IMAGE_TYPE", defaultValue:"spring", description:"base image type")
}
stage('Clone') {
steps {
echo 'Clone'
git branch: 'master', credentialsId: 'credentail id', url: 'pipeline template git 주소'
}
}
stage('Docker Push') {
steps{
sh '''
//registry 로그인
aws ecr get-login-password --region 리전값 | docker login --username AWS --password-stdin ECR주소
cd docker
//도커 빌드
docker build -t base-spring-image ${params.BASE_IMAGE_TYPE}.dockerfile
//도커 태그
docker tag base-doc-image:latest ECR주소/base-doc-image:latest
docker push ECR주소/base-doc-image:latest
'''
}
}
}
이 item 빌드를 시작하면 parameter로 base image type을 받는다
여기에 base image type을 어떤 것으로 할 것인지 결정하면 된다.
그러면 Docker push 스테이지에서 해당 값으로 된 dockerfile을 빌드하게 된다.
만약 python 베이스 이미지에 작업을 했따면 parameter로 python을 넘기면 된다.
이렇게 하면 베이스 이미지를 지속적으로 배포할 수 있는 체계가 만들어 진 것이다.
프로젝트 컨테이너 전체에 영향을 줘야하는 작업이나 베이스 이미지 수정 등을 하나의 dockerfile만 수정한 뒤 해당 파이프라인을 수행하면 베이스 이미지가 수정되고 이를 통해 프로젝트 dockerfile이 수정된 베이스 이미지를 기반으로 컨테이너를 생성하게 될 것이다.
'CICD' 카테고리의 다른 글
[CI/CD Jenkins] Shared Libraries(공유 라이브러리) 활용 (0) | 2023.01.09 |
---|