지속적 통합/지속적 배포 파이프라인이 여러분을 위해 일하게 만드는 방법
도커 기반의 지속적 통합/지속적 배포(이후 CI/CD) 파이프라인은 훌륭한 도구다. 이 도구들은 빠르고 안정적인 배포를 가능하게 해주며, 개발 단계에서 제품 출시까지의 시간을 줄여주고, 팀의 개발 속도도 향상시켜준다.
일반적인 도커 기반의 CI/CD 워크플로우에서는 개발 내용을 버전 관리 시스템에 푸시하면 도커 컨테이너가 자동으로 만들어지고, 테스트된 후, 이미지 레지스트리(사내에 있든 Ducker 허브에 있든 상관 없이)에 푸시된다. CI/CD 시스템에 따라 새 이미지를 스테이징 혹은 프로덕션 서버에 자동으로 배포하기도 하며, 어떤 경우엔 배포 단계를 따로 두기도 한다. 이제부터 언급할 몇몇 모범 사례들은 여러분의 파이프라인을 최대한 활용하는 데 도움이 될 것이다.
1. latest 태그를 사용하지 마라
프로덕션용 CI/CD 시스템을 운용하는 사람이라면 누구나 이 말을 이해하고는 있겠지만, 그래도 언급할 가치가 있다. latest 태그가 붙은 이미지를 프로덕션에 배포하고 있다면 잘못을 저지르고 있는 것이다. latest는 말 그대로 '최신'이라는 의미다. 즉 서버에 문제가 생겼을 때 'latest 바로 전 이미지'를 가리킬 수도 없고, 따라서 롤백도 불가능하다.
최선의 방법은 바로 이미지에 의미 있는 태그를 붙이는 것이다. 너무나 당연한 두 가지 예는 이미지의 버전(myapp:v1.2.7) 혹은 이미지에 들어간 코드의 git 해시값(40d3f6f)을 붙이는 방법이다. git 해시값은 git rev-parse --short 명령으로 알 수 있다.
2. 레이블을 붙여라
git 해시값과 버전은 디버깅할 때도 유용한 정보다. 하지만 태그는 단 하나만 붙일 수 있다. 이렇기 때문에 git 해시값이나 버전 그리고 다른 메타데이터들은 당연히 레이블에 붙여야 한다. 레이블은 Docerfile에 적거나 이미지 빌드시에 추가할 수 있다. (예를 들면, docker build --label org.label-schema.vcs-ref=$(git rev-parse HEAD) …)
디버깅하면서 이러한 메타데이터를 알고 싶다면, 다음과 같이 `docker inspect` 명령을 사용하면 된다.
docker inspect amouat/metadata-test | jq .[0].Config.Labels
{
"org.label-schema.docker.dockerfile": "/opt/Dockerfile",
"org.label-schema.license": "BSD",
"org.label-schema.name": "Metadata Test Container",
"org.label-schema.vcs-ref": "b1a04e77ab0dc130f93f310ed2e03691146fb73d",
"org.label-schema.version": "1.0.7"
}
이 예시에서는 레이블-스킴 표준(http://label-schema.org/)에 따른 필드를 사용했다. 이렇게 메타데이터를 레이블에 붙여 둠으로써, 문제 발생시 원인을 찾기가 쉬워지며 microbadger 같은 유용한 도구를 연동하기도 편해진다.
3. 빌드된 이미지들은 (거의) 재현가능해야 한다
Dockerfile은 훌륭하지만 한 가지 문제가 있다. 내용이 똑같은 Dockerfile로 이미지를 빌드한다 하더라도 결과가 항상 같지는 않다는 점이다. 예를 들어 빌드 도중에 인터넷에서 파일을 다운받는다거나 한다면, 빌드 시점에 따라 다른 파일이 다운로드될 수 있다. apt나 yum 같은 운영체제의 패키지 매니저를 사용하여 소프트웨어를 설치할 때도 비슷한 일이 벌어진다. 다시 말해, 하나의 Dockerfile로 빌드한 이미지라 하더라도 서로 다른 소프트웨어가 설치될 수 있고, 이는 프로덕션 환경에서 예기치 않은 문제의 원인이 될 수도 있다.
Dockerfile 내에서 curl이나 wget으로 다운로드받은 파일이 바뀌지 않았는지 확실히 하고 싶다면, 파일의 체크섬을 검사하는 방법을 사용할 수 있다. Redis 공식 이미지의 Dockerfile에서 하듯이 말이다. 이 방법은 또한 파일 손상이나 악성 코드 변조 등을 막기도 한다.
운영체제에 설치된 패키지가 바뀌지 않게 하려면, 설치 명령에 특정 버전을 명시해야 한다. 예를 들어 다음처럼 하는 대신,
RUN apt install cowsay
아래처럼 하라.
RUN apt install cowsay=3.03+dfsg1-6
이 방식은 베이스 이미지에 대해서도 똑같이 적용된다. 다음처럼 하는 대신,
FROM debian:latest
이렇게 하라.
FROM debian:7.11
이 기법으로도 물론 변경을 완전히 막을 수는 없다는 점을 알아두어야 한다. 다운로드 파일이 깨질 수도 있고, 패키지나 이미지가 이름을 바꾸지 않고도 업데이트될 수도 있다. 이런 문제들을 겪다 보면 로컬 미러를 만들거나 이미지를 확인하는 검수 과정을 추가하기도 할 것이다. 무엇을 하든 교환비용이 든다는 점을 염두에 두라. 소프트웨어 버전을 다운받아둔다면 재현가능성을 얻을 수 있겠지만, 버그 수정이나 기능 추가 등의 자동 업데이트는 불가능해진다.
4. 이미지를 점검(Scan)하라
(* scan을 '점검'으로 번역하기가 살짝 어색하지만, 실제 보안 분야에서 사용하는 용어라서 그대로 따랐습니다)
이미 알려진 보안 취약점을 토대로 이미지를 자동으로 점검(scan)하는 멋진 서비스들이 있다. 이러한 서비스들을 여러분의 지속적 배포 과정에 넣을 수 있고, 넣어야 한다. 이렇게 함으로써 이미지가 만들어질 때마다 자동으로 점검되고, 일종의 '건강검진 보고서'가 생성된다. 아래 이미지는 도커 허브에 있는 debin:latest 이미지에 대한 보안 점검 보고서다.
취약점 목록을 최소한으로 유지함으로써, 시스템에 침투하려는 공격자들의 능력을 철저히 차단할 수 있다. 불행히도 새로운 취약점들이 끊임없이 발견되고 이에 대응하는 업데이트는 시간이 걸리기 때문에, 취약점을 완전히 없애기란 거의 불가능에 가깝다. 따라서 여러분은 각 취약점을 일일이 검사해야 하며, 영향이 있을 것 같다면 영향을 받는 컨테이너를 알아내고 영향을 줄일 수 있는 방법을 찾아야 한다.
여러 서비스가 존재하므로 여러분의 요구사항에 맞는 서비스를 고르기 바란다. 주요 차이점은 서비스가 어디서 돌아가는지(직접 운영인지 원격 서비스인지), 비용, 검사 유형(운영체제 패키지 목록만 스캔하는지 모든 바이너리를 스캔하는지), 기존 도구나 환경과의 통합성 등이다. 몇몇 인기 있는 서비스를 짚어 보자면, CoreOS에서 만든 Clair, Docker Security Scanning, Aqua Security가 만든 Peekr, Twistlock Trust 등이다.
결론
이미지에 의미 있는 태그를 붙이고, 메타데이터는 레이블을 사용하여 추가하고, Dockerfile의 빌드가 재현가능하기 위해 소프트웨어 버전을 고정시키고, 이미지의 보안 취약점을 점검하면, 여러분의 도커 CI/CD 파이프라인은 좀더 효율적이고 신뢰할 만하며 보안에 강해질 것이다.
*****
아드리안 모우앳은 Container Solutions의 수석 과학자다. 작은 웹앱부터 거대한 데이터 분석 소프트웨어에 이르기까지 다양한 분야의 소프트웨어 프로젝트에 참여했다.
원문 : 4 tips for an effective Docker-based workflow
번역 : 김승호(Raccoony)
최신 콘텐츠