플랫폼 개발팀 기술 블로그

Docker : Dockerfile 실습 편 본문

Docker

Docker : Dockerfile 실습 편

DevStream 2019. 3. 22. 14:43

지난 Docker : Dockerfile 편에서는 도커파일의 개념 설명과 도커파일의 생성, 그리고 도커파일을 이용하여 이미지를 만들고 컨테이너를 실행하여 아파치에 접근해보는 간단한 실습을 진행 하였다. 이번 시간에는 도커를 이용하여 Jenkins Slave Node를 생성하여 빌드해보는 실습을 진행 해보고 이 과정을 도커파일로 만들어보도록 하겠다.



Jenkins 분산빌드환경


서버의 자원이 한정된가난한 상태에서 다수의 사람들이 Jenkins(이하 젠킨스)를 통해 빌드를 하다보면 점점 빌드가 잦아지고 결국 빌드를 대기하는 일종의 빌드 병목현상이 발생한다. 게다가 몸집이 큰 프로젝트 파일을 빌드하기 위해서 상당한 시간이 소요되는 경우도 있어서 빌드를 기다리기보다 수동빌드를 하는게 더 나은 상황이 발생 할 수 있다.


이를 분산빌드환경(Slave Node 추가)을 통하여 해결 해보도록 하자.



먼저 젠킨스 메인 화면의 좌측 Jenkins 관리를 누르고 아래로 스크롤하여 노드관리 메뉴로 진입한다. 신규 노드를 눌러 노드명을 입력하고 Permanent Agent 선택 후 OK를 누르면 아래 상세정보 입력 화면으로 이동한다. 필자는 Slave Node Name을 m7Docker라고 입력하였다. Credentials 에는 Docker 컨테이너에 접근할 계정을 Add를 눌러 입력해주면 된다. 필자는 ID는 root에 비밀번호는 xptmxm123으로 입력 후 저장하였다. 이후 이미지에는 나와있지 않지만 필자는 SSH 포트를 8890으로 변경해주었다 (고급버튼 누르면 포트변경 가능)




Jenkins Build를 위한 Slave Node용 도커 컨테이너 생성


다음은 Ubuntu 16.04를 이용하여 젠킨스 서버에서 도커 컨테이너로 SSH로 접근 후 maven 빌드를 수행하는 컨테이너 하나를 만들어보도록 하겠다. 이미지 생성과 컨테이너 생성은 이미 한번 다룬 내용이므로 너무 자세한 설명은 생략 하고 명령어 위주로 작성하겠다.


먼저 docker run명령을 통해 컨테이너를 생성하자 포트포워딩은 젠킨스 slave설정에서 지정해둔 8890 포트와 도커 컨테이너에 접근할 22번 포트를 서로 연결하였다.


[root@localhost testuser]# docker run -i -t -p 8890:22 --name jenkins_slave docker.io/ubuntu:16.04
root@8d8eeb87e586:/#


이제 이 아무것도 없는 도커 컨테이너를 젠킨스 Slave Node로 활용하기 위해 무엇을 해야할까 한번 정리 해보자.


1. 패키지 업데이트

2. 컨테이너 접근을 위한 ssh 설치

3. 빌드를 위한 maven 설치

4. 소스변경사항을 가져오기 위한 git 설치

5. jdk11이 적용된 프로젝트의 빌드를 위해 openjdk11 설치

6. root 계정을 사용하기 위해 root 패스워드 설정

7. ssh로 root접근이 가능하도록 sshd_config파일의 옵션 수정

8. Jenkins 전역설정의 JAVA_HOME과 MAVEN_HOME의 경로 동기화


이정도가 되겠다. 먼저 패키지 업데이트부터 차근차근 진행 해보자.



1. 패키지 업데이트


root@8d8eeb87e586:/# apt-get update Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB] Get:2 http://security.ubuntu.com/ubuntu xenial-security InRelease [109 kB] Get:3 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] ... ... Fetched 15.7 MB in 1min 3s (248 kB/s) Reading package lists... Done



2. SSH 설치


root@8d8eeb87e586:/# apt-get install -y openssh-server Reading package lists... Done Building dependency tree Reading state information... Done ... ... Setting up ssh-import-id (5.5-0ubuntu1) ... Processing triggers for libc-bin (2.23-0ubuntu11) ... Processing triggers for ca-certificates (20170717~16.04.2) ... Updating certificates in /etc/ssl/certs... 148 added, 0 removed; done. Running hooks in /etc/ca-certificates/update.d... done. Processing triggers for systemd (229-4ubuntu21.16) ...



3. Maven 설치


root@8d8eeb87e586:/# apt-get install -y maven Reading package lists... Done Building dependency tree Reading state information... Done ... ... After this operation, 156 MB of additional disk space will be used. Get:1 http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 libjpeg-turbo8 amd64 1.4.2-0ubuntu3.1 [111 kB] Get:2 http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 x11-common all 1:7.7+13ubuntu3.1 [22.9 kB] Get:3 http://archive.ubuntu.com/ubuntu xenial/main amd64 libxtst6 amd64 2:1.2.2-1 [14.1 kB] ... ... done.



4. Git 설치


root@8d8eeb87e586:/# apt-get install -y git-core Reading package lists... Done Building dependency tree Reading state information... Done Get:1 http://archive.ubuntu.com/ubuntu xenial/main amd64 libatm1 amd64 1:2.5.1-1.5 [24.2 kB] Get:2 http://archive.ubuntu.com/ubuntu xenial/main amd64 libmnl0 amd64 1.0.3-5 [12.0 kB] Get:3 http://archive.ubuntu.com/ubuntu xenial/main amd64 libpopt0 amd64 1.16-10 [26.0 kB] ... ... update-alternatives: using /usr/bin/file-rename to provide /usr/bin/rename (rename) in auto mode Processing triggers for libc-bin (2.23-0ubuntu11) ... Processing triggers for systemd (229-4ubuntu21.16) ...



5. OpenJdk 11 설치 (필자는 11.0.1 버전을 사용하였다.)


root@8d8eeb87e586:/# wget -P /usr/local https://download.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz --2019-03-22 01:15:09-- https://download.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz Resolving download.java.net (download.java.net)... 23.212.14.196 Connecting to download.java.net (download.java.net)|23.212.14.196|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 187599951 (179M) [application/x-gzip] Saving to: '/usr/local/openjdk-11.0.1_linux-x64_bin.tar.gz' openjdk-11.0.1_linux-x64_bin.tar.gz 100%[===================================================================================================================>] 178.91M 22.2MB/s in 8.7s 2019-03-22 01:15:23 (20.5 MB/s) - '/usr/local/openjdk-11.0.1_linux-x64_bin.tar.gz' saved [187599951/187599951] root@8d8eeb87e586:/# cd /usr/local/ && tar -xzf openjdk-11.0.1_linux-x64_bin.tar.gz && rm openjdk-11.0.1_linux-x64_bin.tar.gz root@8d8eeb87e586:/usr/local# ls bin etc games include jdk-11.0.1 lib man sbin share src root@8d8eeb87e586:/usr/local#



6. root 패스워드 설정


root@8d8eeb87e586:/usr/local# passwd root Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully root@8d8eeb87e586:/usr/local#



7. sshd_config 설정파일 수정 (ssh로 root계정에 접근하기 위한 설정 변경)


root@8d8eeb87e586:/usr/local# vi /etc/ssh/sshd_config bash: vi: command not found



당황하지 말고 vi에디터를 설치 해주도록 한다.


7-1. vi에디터 설치


root@8d8eeb87e586:/usr/local# apt-get install vim Reading package lists... Done Building dependency tree Reading state information... Done ... ... Processing triggers for libc-bin (2.23-0ubuntu11) ...



7-2. sshd_config 파일 수정 (PermitRootLogin의 prohibit-password설정을 yes로 바꾼 후 저장한다.)


root@8d8eeb87e586:~# vi /etc/ssh/sshd_config

... ...

# Authentication: LoginGraceTime 120 PermitRootLogin prohibit-passwordyes ... ... :wq



8. Jenkins 전역 설정에 맞추어 JAVA_HOME과 MAVEN_HOME 경로 설정


필자는 JDK는 /usr/local/jdk-11.0.1에 저장 하였고(다운로드 및 압축해제는 위의 설정과 같으므로 JAVA_HOME은 별 다른 설정이 필요하지 않다.) maven은 /usr/share/maven 폴더에 저장이 되어있는데 /usr/local/apache-maven-3.5.3의 경로로 심볼릭링크를 걸어두었다.


root@8d8eeb87e586:~# ln -s /usr/share/maven /usr/local/apache-maven-3.5.3



이제 모든 준비가 완료 되었다. Jenkins 서버에서 현재 설정해둔 도커 컨테이너로의 접근이 가능한지 확인 해보자. 먼저 Jenkins 서버에서 필자의 컨테이너에 접근하기 위해서는 외부에서 접근이 가능하도록 포트를 열어 주어야 한다. 필자는 윈도우 10을 기준으로 설명하겠다. 먼저 방화벽의 인바운드 설정에서 아까 도커 컨테이너 생성 시 포트포워딩 했었던 8890을 지정해준다.




인바운드설정이 완료되면 8890으로 들어온 포트를 내부의 어떤 IP로 포워딩 할지 지정 해주어야 하는데 윈도우 커멘드를 관리자 권한으로 접근하여 포트 포워딩을 설정 해주도록 한다.


C:\WINDOWS\system32>netsh interface portproxy add v4tov4 listenport=8890 listenaddress=192.168.70.22 connectport=8890 connectaddress=172.17.100.97 C:\WINDOWS\system32>netsh interface portproxy show v4tov4 ipv4 수신 대기: ipv4에 연결: 주소 포트 주소 포트 --------------- ---------- --------------- ---------- 192.168.70.22 8890 172.17.100.97 8890



192.168.70.22:8890으로 들어온 포트를 필자의 컴퓨터 내부 IP인 172.17.100.97:8890으로 보낸다는 의미이다. Jenkins 서버에서 필자의 도커 컨테이너까지의 접근은 아래 이미지를 참고하기 바란다.




이제 젠킨스 Slave Node를 실행하여 도커 컨테이너로 접근해보자. ssh로 접근하기 위해 ssh service를 활성화 시켜준다.


root@8d8eeb87e586:~# service ssh start * Starting OpenBSD Secure Shell server sshd


ssh service 활성화가 완료되면 젠킨스에서 아까 생성한 m7Docker에 진입 후 Launch agent버튼을 눌러 Slave Node를 실행시킨다.



아래와 같은 로그가 올라온다면 ssh접속에 성공한것이다.


[03/22/19 12:21:07] [SSH] Opening SSH connection to 192.168.70.22:8890.

... ...

[03/22/19 12:21:07] [SSH] Starting sftp client. [03/22/19 12:21:07] [SSH] Remote file system root /jenkins does not exist. Will try to create it... [03/22/19 12:21:07] [SSH] Copying latest slave.jar... [03/22/19 12:21:07] [SSH] Copied 771,004 bytes. Expanded the channel window size to 4MB [03/22/19 12:21:07] [SSH] Starting slave process: cd "/jenkins" && java -jar slave.jar <===[JENKINS REMOTING CAPACITY]===>channel started Remoting version: 3.21 This is a Unix agent Evacuated stdout Agent successfully connected and online



이제 젠킨스 빌드 시 이 Slave Node를 활용하겠다는 설정을 해주어야 하는데 프로젝트 진입 → 구성 → Restrict where this project can be run을 체크하고 위에서 생성했던 m7Docker 를 입력하여 저장해준다.



이제 빌드를 진행 해보자.



m7Docker Slave Node에서 빌드가 정상적으로 진행되었다.



지금까지의 과정들은 도커파일을 사용하면 현재 도커 컨테이너와 동일한 설정이 담긴 이미지를 한번에 생성 할 수 있다. 도커파일의 생성방법은 지난 시간에 설명하였으므로 이번 시간에는 도커파일의 스크립트 설명과 직접 도커파일을 빌드하여 이미지를 생성하고 컨테이너에 SSH접근까지만 확인하도록 하겠다.

# Ubuntu 16.04버전을 기반으로 함
FROM ubuntu:16.04

# 다운로드 링크, 파일명, maven 버전 등 변경이 필요한 경우를 대비해 변수로 선언해준다.
ARG jdkFileName=openjdk-11.0.1_linux-x64_bin.tar.gz
ARG jdkDownloadUrl=https://download.java.net/java/GA/jdk11/13/GPL/${jdkFileName}
ARG mavenHome=/usr/local/apache-maven-3.5.3
ARG userName=root
ARG userPassword=xptmxm123

# 패키지 목록 최신화 후 원격 접속을 위한 ssh와 빌드를 위한 maven 및 변경내역을 가져올 git을 설치한다.
RUN apt-get update
RUN apt-get install -y openssh-server
RUN apt-get install -y maven
RUN apt-get install -y git-core

# 현재 jenkins 전역설정에서 maven의 경로는 /usr/local/apache-maven-3.5.3 으로 지정 해두었다.
# ln -s 명령을 사용하여 심볼릭 링크를 걸어준다.
RUN ln -s /usr/share/maven ${mavenHome}

# service 및 api의 빌드는 jdk11이 필요하므로 다운로드 받고 압축을 풀어준다.
RUN wget -P /usr/local ${jdkDownloadUrl}
RUN cd /usr/local/ && tar -xzf ${jdkFileName} && rm ${jdkFileName}

# root 계정을 사용할 것이므로 root계정의 비밀번호 설정 및 root계정으로 ssh접근이 가능하도록 수정한다.
RUN echo "${userName}:${userPassword}" | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# 컨테이너 시작 시 ssh서비스를 Active 시키기 위해 ENTRYPOINT를 지정 해둔다
ENTRYPOINT service ssh restart && /bin/bash

# 외부에서 접근이 가능한 포트를 지정해준다. ssh접속이므로 22번 포트 설정
EXPOSE 22


이제 해당 도커파일을 기반으로 이미지를 생성해보자. 도커파일을 빌드하고 이미지가 잘 생성되었는지 확인해보자.


[root@localhost test2]# docker build -t docker_img ./ ... ... ---> aba77358024b Removing intermediate container 490098d7f585 Step 16/17 : ENTRYPOINT service ssh restart && /bin/bash ---> Running in 22cd10713ee8 ---> 98e07e4fc4b5 Removing intermediate container 22cd10713ee8 Step 17/17 : EXPOSE 22 ---> Running in bcf569c735cc ---> 07f9b213b807 Removing intermediate container bcf569c735cc Successfully built 07f9b213b807 [root@localhost test2]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker_img latest 07f9b213b807 3 minutes ago 939 MB docker.io/ubuntu 16.04 9361ce633ff1 10 days ago 118 MB apache_img first d307433464d8 2 weeks ago 390 MB layer_test second 127ab2a39585 4 weeks ago 188 MB layer_test first 48f47ef8257d 4 weeks ago 188 MB docker.io/ubuntu 14.04 5dbc3f318ea5 8 weeks ago 188 MB


새로만든 이미지로 docker run 명령을 실행하기 전에 이전에 켜두었던 jenkins_slave 컨테이너는 종료 하도록 한다. (포트가 겹치므로)


[root@localhost test2]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8d8eeb87e586 docker.io/ubuntu:16.04 "/bin/bash" 19 hours ago Up 4 hours 0.0.0.0:8890->22/tcp jenkins_slave dcc887cf8b0b apache_img:first "apachectl -D FORE..." 2 weeks ago Exited (137) 2 days ago apache_test d33a60d75c45 layer_test:first "/bin/bash" 4 weeks ago Exited (255) 2 weeks ago layer_test2 c73025587f2b ubuntu:14.04 "/bin/bash" 4 weeks ago Exited (0) 4 weeks ago layer_test [root@localhost test2]# docker stop jenkins_slave jenkins_slave [root@localhost test2]#


이제 새로운 이미지로 컨테이너를 생성하도록 한다.
실행이 잘 되었다.


[root@localhost test2]# docker run -i -t -p 8890:22 --name jenkins_slave2 docker_img:latest * Restarting OpenBSD Secure Shell server sshd [ OK ] root@72f83424f1dc:/#


이제 젠킨스에 다시 들어가서 Launch Agent 버튼을 눌러 SSH 접근이 가능한지 확인해보자.

아래 이미지가 출력되면 SSH접속에 성공한것이다.



여기까지 젠킨스 도커 컨테이너를 활용한 Slave Node의 생성과 빌드를 해보고 이 과정을 도커파일로 만들어 이미지를 생성하고 컨테이너 화 하는 실습까지 진행 해보았다. 이미지를 그대로 내려받았을때 세부설정에 대한 변경이 필요한 경우가 있을것이다. 이 때마다 컨테이너를 만들고 설정을 바꿔 다시 commit명령으로 새로운 이미지를 만드는 과정이 생길 수 있는데 도커파일을 활용하면 이러한 낭비를 없앨 수 있다. 또한 도커파일은 설정만 바꾸어 여러대의 서버에 적용하여 사용하는 경우에도 효과적으로 사용할 수 있다.




Docker : Dockerfile 실습 편

끝.



'Docker' 카테고리의 다른 글

Docker : 도커스웜 클러스터 구축 편  (2) 2019.05.17
Docker : 컨테이너 오케스트레이션 개요 편  (0) 2019.04.19
Docker : Dockerfile 편  (0) 2019.03.07
Docker : 이미지 편  (0) 2019.02.22
Docker : 컨테이너 편  (1) 2019.02.15
Comments