오늘날 개발되고 상용화된 대부분의 서비스들은 어떤 천재 혼자 뚝딱 만들어 낸 것이 아니다. 다양한 특기를 가진 다양한 사람들이 함께 품어 만들어낸 불교의 사리 같은 것이다. 그리고 자연스럽게 가뜩이나 어려운 일의 중간 과정이 진짜 알맹이를 가로막지 않도록 여러 도구와 개념들이 등장했는데, 그 중 하나가 지속적으로 코드의 품질을 관리할 수 있고, 또 나아가 배포까지 이어질 수 있는 CI와 CD (Continuous Integration / Continuous Delivery)다. 내가 작성한 코드를 그대로 내 컴퓨터에서 테스트하고 사용한다면 아무 상관 없는 이야기겠지만, 여러 팀원이 함께 코드를 작성하는 환경에서는 각종 이슈와 신규 배포의 진행사항을 기록하는 일도 필요하고, 내가 사용하지 않는 개발환경을 요구하는 코드를 빌드할 일도 생긴다. 이런 여러가지 문제를 다 내려놓고. 일단 귀찮다. 하루이틀도 아니고 이 모든 일들을 매일 반복한다고 생각해보자. 말 그대로의 주객전도다.

위에서 언급한 CI와 CD의 개념은 이런 문제들을 해결하기 위해 탄생했다. 그리고 가장 대중적인 도구로 Jenkins를 뽑을 수 있겠다. 이미 전세계 다양한 팀에서 Jenkins를 사용해 자신들의 코드를 자동 빌드하고, 테스트하고, 변경점을 기록하고 있다. 필자는 어딘가의 팀에서 개발자로 활동하고 있지 않지만, 평소 취미 목적으로 만드는 소프트웨어들을 개인 노트북에서 코딩해 Docker 이미지로 빌드한 후, Docker Hub 저장소를 통해 개인 서버들로 전송해 구동하는 과정을 자주 거치고 있어 귀차니즘을 참지 못하고 Jenkins에 손을 대게 되었다.

DinD (Docker-in-Docker)


지금부터 하나 재미있는 시도를 해보자. 바로 Jenkins를 Docker 컨테이너로 구동한 후, 그 컨테이너 안에 또 Docker 데몬을 구동해 도커 안의 도커 환경을 만들어 볼 거다. Jenkins 컨테이너가 자체적으로 Docker 이미지를 생성할 수 있게 만드는 거다. Git에 새로운 코드를 커밋하면 Jenkins가 이를 감지하고 자동으로 Docker 이미지를 생성해, 업로드까지 해주는 구성을 해보자.

필자는 관련 정보를 검색하던 중 발견한 Seapy님의 Docker 이미지를 사용했다. Docker Hub에 공개된 여러 이미지들을 테스트해봤으나 이 이미지가 가장 깔끔하고 사용하기 편해 그대로 사용하고 있다. 다른 이미지를 사용할 예정이거나, 혹은 직접 이미지를 빌드해 사용하고 싶다고 해도 기본적인 설정 방법은 같으니, 참고하길 바란다.

호스트 컴퓨터에서, 아래 명령어를 통해 이미지를 다운받고 실행해보자.

docker run -p 연결할_포트번호:8080 -v 연결할/경로:/var/jenkins_home --privileged seapy/jenkins-dind:1.554.3

위의 연결할_포트번호에는 웹 브라우저에서 접근 시 사용할 포트번호를, 연결할/경로에는 Jenkins 컨테이너의 /var/jenkins_home 폴더와 연결될 호스트 컴퓨터의 폴더 경로를 입력한다. Docker 컨테이너는 일반적으로 컨테이너가 변형될 경우 안의 데이터의 안전을 장담할 수 없는 구조라 이렇게 호스트 컴퓨터의 폴더를 연결해두면 컨테이너에 문제가 생겨도 데이터는 안전하게 지킬 수 있다.

중간에 다른 문제가 발생하지 않았다면, 정상적으로 컨테이너가 구동되고 웹 브라우저로 Jenkins에 접근도 잘 될 것이다. 사용한 이미지가 조금 연식이 있어 (마지막 업데이트가 년단위 전이다…) Jenkins도 구버전이 구동되어 있을 것인데, 사실 이 상태로도 정상적인 사용은 가능하다. 귀찮은 사람은 이대로 사용하고, 최신 버전을 사용하지 못하면 온몸에 가시가 돋는 얼리어답터 분들은 docker execattach 명령 등을 통해 해당 컨테이너에 Java8를 설치한 후 웹 콘솔에서 업데이트 버튼을 누르면 된다. 최신 버전의 Jenkins는 Java8를 요구하는데, 이 이미지에 설치된 구버전은 Java7만 사용하고 있기 때문이다. 꼭 기억하길 바란다. 컨테이너는 일종의 프로세스 개념이라, Java8이 없어 다운받은 업데이트 파일을 정상적으로 구동하지 못할 경우 컨테이너가 그대로 꺼져버린다. 괜히 삽질하지 마시길.

자, 그대로 사용하시던 혹은 업데이트를 하셨던, 이제 우리의 알맹이를 공략하자. Jenkins 웹 콘솔에서 새로운 Item 버튼을 타고 프로젝트 생성 페이지로 넘어가보자. 프로젝트 이름을 입력하고, Freestyle project를 누르면 된다.

혹시 최신 버전의 Jenkins로 업데이트한 후, 새로운 Item 버튼을 누르면 빈 페이지만 보일 경우, Jenkins 관리 -> 플러그인 관리 메뉴에 들어가 External Job Monitor을 최신 버전으로 업데이트하면 된다. 이 버그리포팅을 참조하면 도움이 될 것이다.

상세 구성을 할 수 있는 페이지가 나올건데, 소스 코드 관리 라는 항목에서 Git을 선택하고 자신의 저장소 URL과 인증 정보 등을 입력한다. 필자는 BitBucket을 연동할 생각이기에 그 아래 항목의 빌드 유발 항목에서 Build when a change is pushed to BitBucket 을 선택했다.

필자처럼 BitBucket을 사용할 경우 프로젝트 생성 전 Jenkins 관리 -> 플러그인 관리 메뉴에서 BitBucket 플러그인을 미리 설치해둬야 한다. 설치하지 않을 경우 위 항목이 보이지 않는다.

아래의 빌드 항목에는 직접 실행 가능한 쉘 명령어를 입력할 수 있는데, 아래처럼 이미지 생성 후 업로드하는 명령어를 지정하면 된다.

docker build -t 저장소명/이미지명 .

docker push 저장소명/이미지명


모두 설정을 마쳤을 경우 아마 위 이미지와 비슷할 것이다. 저장을 눌러 빠져나오자.

이제 테스트 타임이다! 코드에 변경점을 준 뒤 Git에 업로드한 뒤 두근두근 기다리면 된다. 정상적으로 과정을 따라왔다면, 아마 별 문제 없이 빌드와 배포 과정이 진행될 것이다.

자동화 별 것 없네

수고하셨다. 자동화 생각보다 별 것 없다. 여러분은 약간의 시간을 투자하여 매일 반복하는 지루한 작업을 줄인 참된 인간이 된 것이다. 이 글에서는 Docker 이미지의 자동 빌드 & 배포만 예시로 들었지만, 이 환경을 기반으로 어떤 종류의 자동화도 할 수 있으니 이제 본인 편의에 맞게 커스터마이징 해나가면 된다.

Knock ‘em dead!