> ## Content Index
> Fetch the complete content index at: https://www.popit.kr/llms.txt
> Use this file to discover other available public pages before exploring further.

# 스타트업 개발자 혼자 빠르게 싸게 서버 구축하기 - 4편 빌드와 배포
- URL: https://www.popit.kr/startup-solo-server-setup-4-build-deploy/
- Published: 2020-12-09T21:25:57.000Z
- Updated: 2020-12-09T21:25:57.000Z
- Author: 유 영모
- Tags: #소프트웨어, 도커, 배포, jenkins, 빌드, Gitlab, deploy

---

- [스타트업 개발자 혼자 빠르게 싸게 서버 구축하기 - 1편](https://www.popit.kr/startup-solo-server-setup-1/)
- [스타트업 개발자 혼자 빠르게 싸게 서버 구축하기 - 2편](https://www.popit.kr/startup-solo-server-setup-2/)
- [스타트업 개발자 혼자 빠르게 싸게 서버 구축하기 - 3편](https://www.popit.kr/startup-solo-server-setup-3/)
- **스타트업 개발자 혼자 빠르게 싸게 서버 구축하기 - 4편**

---

[지난 3편](https://www.popit.kr/startup-solo-server-setup-3/)에서는 애플리케이션을 빌드/배포할 때 호스트 서버에 [쉘 스크립트Shell script](https://en.wikipedia.org/wiki/Shell%5Fscript?ref=popit.kr)를 만들어 사용했다.

> 워드프레스와 마찬가지로 개발 서버 역시 도커를 사용한다. 왜냐하면 하나의 서버에 여러 서비스를 올리는 경우 SDKSoftware development kit나 소프트웨어 라이브러리 버전 충돌 같은 문제가 일어날 수 있는데 도커를 사용하면 도커 컨테이너간 가상 머신처럼 서비스가 격리 되어 여러 서비스를 쉽게 올릴 수 있기 때문이다.  
>  
>  
>  
>  
> 프로젝트마다 도커 이미지를 만드는 Dockerfile은 모두 다르기 때문에 이 글에서 다루지 않는다.  
>  
>  
> 도커 이미지 저장소를 활용하거나 젠킨스 같은 빌드 도구를 이용할 수도 있겠지만 구성하는 것도 일이어서 필자는 호스트 서버에 아래와 같은 간단한 쉘 스크립트(deploy-api-server.sh)를 만들었다.  
>  
>  
> **간단하게 설명하면 호스트 서버에서 최신 소스 코드를 받아 도커 이미지를 만들고 바로 실행하는 것이다.**  
> \- [/startup-solo-server-setup-3/](https://www.popit.kr/startup-solo-server-setup-3/)

쉘 스크립트는 간단하다는 장점이 있지만 스크립트 실행 이력 관리가 어렵고 다른 개발자가 스크립트를 실행하기 위해 직접 호스트 서버에 접속해야 하는 불편함이 따른다.

이 글은 쉘 스크립트를 개발자가 직접 실행하는 대신 [젠킨스Jenkins](https://www.jenkins.io/?ref=popit.kr)를 이용하고 더불어 [사설 깃랩 저장소Private GitLab Repository](https://about.gitlab.com/?ref=popit.kr)로부터 소스코드를 체크아웃 받아 호스트 서버에 도커 이미지를 만들고 배포하는 방식을 소개한다.

![image-20201109-222458](https://www.popit.kr/content/images/wp/2020/12/image-20201109-222458.png)

# 젠킨스 설치

젠킨스를 직접 호스트 서버에 설치하지 않고 도커 컨테이너 방식으로 설치하고 실행한다. 그 이유는 젠킨스를 실행하기 위한 의존성(예. Java)을 호스트 서버에서 격리시키기 위해서이다.

호스트 서버에 아래 도커 명령어를 실행한다.  

```sh
# 1. 젠킨스 도커 이미지 다운로드
docker pull jenkins/jenkins:lts

# 2. 젠킨스 실행
docker run -d \
 -p 8181:8080 \
 -v /var/jenkins_home:/var/jenkins_home \
 --name jenkins -u root jenkins/jenkins:lts
```

여기서 주목해야 할 점은 '-v /var/jenkins\_home:/var/jenkins\_home' 부분이다. 도커를 실행(run)할 때 [볼륨Volumes 옵션](https://docs.docker.com/engine/reference/commandline/run/?ref=popit.kr)으로 호스트 디렉토리(/var/jenkins\_home)와 도커 컨테이너 디렉토리(/var/jenkins\_home)를 공유했다. 젠킨스 도커 컨테이너가 예기치 않게 중단되어 삭제되더라도 젠킨스에서 사용했던 데이터는 남아 있어야 하기 때문이다.

웹 브라우저로 젠킨스에 접속하면 아래와 같은 화면이 나타난다.

![image-20201012-232410](https://www.popit.kr/content/images/wp/2020/12/image-20201012-232410-1024x605.png)

Administrator password를 요구하는데 '/var/jenkins\_home/secrets/initalAdminPassword'에서도 찾을 수 있지만 아래 명령어로 젠킨스 도커 컨테이너의 로그에서도 확인할 수 있다.  

```
docker logs -f jenkins
```

![image-20201109-231311](https://www.popit.kr/content/images/wp/2020/12/image-20201109-231311.png)

Administrator password를 입력하면 플러그인 선택 화면에 나오고 계속 진행한다.

![image-20201012-232636](https://www.popit.kr/content/images/wp/2020/12/image-20201012-232636-1024x759.png)

![image-20201012-232645](https://www.popit.kr/content/images/wp/2020/12/image-20201012-232645-1024x759.png)

마지막으로 Admin User를 생성한다.

![image-20201012-232954](https://www.popit.kr/content/images/wp/2020/12/image-20201012-232954-1024x751.png)

![image-20201012-233013](https://www.popit.kr/content/images/wp/2020/12/image-20201012-233013-1024x759.png)

# 사설 깃랩 저장소에서 코드 체크아웃 하기

공개 저장소에서 코드를 체크아웃 할 때에는 별도의 인증이 필요하지 않지만 사설 저장소는 인증이 필요하다.

다양한 인증 방식이 있지만 필자는 깃랩에서 제공하는 [Deploy Keys](https://docs.gitlab.com/ee/user/project/deploy%5Fkeys/?ref=popit.kr) 방식을 선택했다.

> Deploy keys allow read-only or read-write (if enabled) access to one or more repositories, by importing an SSH public key to your GitLab instance.  
> This is useful for cloning repositories to your Continuous Integration (CI) server. By using deploy keys, you don’t have to set up a fake user account. - [https://docs.gitlab.com/ee/user/project/deploy\_keys/](https://docs.gitlab.com/ee/user/project/deploy%5Fkeys/?ref=popit.kr)

[SSHSecure Shell](https://en.wikipedia.org/wiki/SSH%5F%28Secure%5FShell%29?ref=popit.kr) 키를 깃랩에 등록 후 젠킨스에서 코드 체크아웃을 받을 때 특정 사용자 계정이 아니라 SSH키를 사용한다.

### 1\. SSH 키 생성

먼저 Deploy Key로 사용할 SSH 키를 생성한다. 호스트 서버에서 [ssh-keygen](https://www.ssh.com/ssh/keygen/?ref=popit.kr) 명령어로 생성한다. 여기서 passphrease를 물어보는데 입력하지 않고 계속 엔터를 쳐서 패스워드를 없게 만든다.

![image-20201012-233134](https://www.popit.kr/content/images/wp/2020/12/image-20201012-233134.png)

홈디렉토리의 .ssh 디렉토리에 아래와 같이 SSH 개인키(id\_rsa)와 공개키(id\_rsa.pub) 한 쌍이 생성된 것을 확인할 수 있다.

![image-20201012-233358](https://www.popit.kr/content/images/wp/2020/12/image-20201012-233358.png)

![image-20201012-233513](https://www.popit.kr/content/images/wp/2020/12/image-20201012-233513.png)

### 2\. 깃랩 리파지토리Repository에 Deploy Key 등록

깃랩 좌측 메뉴 Settings → Repository 를 선택하면 Deploy Keys를 등록할 수 있다. Title 항목에 이름을 입력하고 Key 항목에는 앞에서 생성한 공개키(id\_rsa.pub)를 넣는다.

![image-20201115-215530](https://www.popit.kr/content/images/wp/2020/12/image-20201115-215530-1024x650.png)

### 3\. 젠킨스 자격Credentials 등록과 사용

젠킨스 좌측 메뉴의 ‘새로운 Item’을 선택한다.

![image-20201116-212645](https://www.popit.kr/content/images/wp/2020/12/image-20201116-212645-1024x746.png)

![image-20201013-000919](https://www.popit.kr/content/images/wp/2020/12/image-20201013-000919-1024x825.png)

젠킨스 Item ‘소스 코드 관리’ 항목에 사설 깃랩 저장소를 입력하면 인증을 하지 않았기 때문에 아래와 같이 빨간 글씨로 에러가 나는 것을 확인할 수 있다. Credentials 항목 ‘Add’를 선택한다.

![image-20201116-213008](https://www.popit.kr/content/images/wp/2020/12/image-20201116-213008-1024x825.png)

Private Key 항목에 앞서 생성했던 SSH 개인키(id\_rsa)를 등록한다.

![image-20201116-213055](https://www.popit.kr/content/images/wp/2020/12/image-20201116-213055-1024x825.png)

생성한 Credentials(gitlab)를 선택하면 오류가 없어진 것을 확인할 수 있으며 ‘저장’ 후 ‘Build Now’를 클릭하면 코드를 체크아웃 받는 것을 확인할 수 있다.

![image-20201116-220312](https://www.popit.kr/content/images/wp/2020/12/image-20201116-220312-1024x825.png)

# 젠킨스에서 도커 사용하기

도커 이미지 만들기 위해 젠킨스에서 docker 명령어를 사용하면 docker 명령어를 찾을 수 없다는 오류가 난다.

![image-20201116-214618](https://www.popit.kr/content/images/wp/2020/12/image-20201116-214618-1024x593.png)

그 이유는 **젠킨스 도커 컨테이너 안에 도커가 없기 때문**이다.

![image-20201116-215148](https://www.popit.kr/content/images/wp/2020/12/image-20201116-215148.png)

젠킨스 도커 컨테이너 언에서 도커를 쓰려면 **젠킨스 도커 컨테이너 안에 도커를 설치**해야 한다.

젠킨스 도커 컨테이너에서 직접 도커를 설치\[1\]할 수도 있겠지만 이렇게 만들어진 이미지는 삭제되면 다시 작업을 해주어야 하기 때문에 유지보수를 위해서는 아래와 같이 Dockerfile을 하나 만들고 따로 이미지를 만들어서 사용하는 것이 좋다.  

```
FROM jenkins/jenkins:lts

USER root

RUN apt-get update
RUN apt-get -y install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
RUN add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu cosmic stable"
RUN apt-get update
RUN apt-get -y install docker-ce docker-ce-cli containerd.io

ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/jenkins.sh"]
```

위에서 만든 Dockefile 아래 명령어를 사용하여 빌드하고 빌드한 이미지로 다시 젠킨스를 실행한다.  

```
# 1. 젠킨스 이미지 빌드
docker build --tag my-jenkins:latest .

# 2. 젠킨스 실행
docker run -d \
 -p 8181:8080 \
 -v /var/jenkins_home:/var/jenkins_home \
 --name jenkins -u root my-jenkins:latest
```

# 문제는 해결되었지만…

이제 젠킨스에서 Docker 명령어를 사용할 수 있지만 또 다른 중요한 문제가 남는다.

젠킨스에서 코드를 체크아웃 받아 Docker 명령어로 빌드하면 **도커 이미지가 호스트 서버가 아닌 젠킨스 컨테이너 안에 생성**된다. 그 이유는 젠킨스가 컨테이너 내부의 Docker Daemon을 따로 쓰고 있기 때문이다.

![image-20201208-003901](https://www.popit.kr/content/images/wp/2020/12/image-20201208-003901.png)

필자가 바라는 것은 젠킨스 도커 컨테이너 안에서 애플리케이션이 실행되는 것이 아니다. 호스트 서버에서 도커로 실행하는 것이다.

# /var/run/docker.sock

도커를 설치하면 '/var/run/docker.sock' 파일이 만들어진다. docker.sock은 유닉스 소켓으로 도커 데몬과 통신하는데 사용하는데 **docker.sock을 공유하면 젠킨스 도커 컨테이너 안에서 호스트 서버의 도커 데몬을 사용할 수 있다.**

젠킨스를 실행할 때 볼륨 옵션을 추가하여 호스트 서버의 docker.sock을 컨테이너에 공유한다.  

```
docker run -d \
 -p 8181:8080 \
 -v /var/jenkins_home:/var/jenkins_home \
 -v /var/run/docker.sock:/var/run/docker.sock \
 --name jenkins -u root my-jenkins:latest
```

젠킨스 도커 컨테이너 안에서 docker ps 명령어를 실행하면 호스트 서버의 도커 컨테이너들을 확인할 수 있다.

![image-20201105-235139](https://www.popit.kr/content/images/wp/2020/12/image-20201105-235139-1024x77.png)

# 덤

젠킨스를 사용하면서 한국 시간대로 보여지길 원한다면 젠킨스 실행할 때 '-e TZ=Asia/Seoul' 옵션을 추가한다.  

```
docker run -d \
 -p 8181:8080 \
 -v /var/jenkins_home:/var/jenkins_home \
 -v /var/run/docker.sock:/var/run/docker.sock \
 -e TZ=Asia/Seoul \
 --name jm_jenkins -u root my-jenkins:latest
```

# 주석

\[1\] [https://docs.docker.com/engine/install/ubuntu/](https://docs.docker.com/engine/install/ubuntu/?ref=popit.kr)