::: IT인터넷 :::

Docker로 Jenkins의 Python 빌드 에이전트 만들기

곰탱이푸우 2021. 8. 12. 08:20

시놀로지 NAS는 리눅스 기반의 운영체제를 기반으로 한 DSM으로 동작한다.
시놀로지 NAS에 Docker를 기반으로 셋팅한 Jenkins 역시 리눅스 기반이다.

 

시놀로지 NAS에 Jenkins 구축하기

현재 근무 중인 회사에서는 빌드 및 배포 시스템으로 Atlassian의 Bamboo를 사용 중이다. 기능도 익숙하고 사용하기 편리하지만 상용 제품이다 보니 개인이나 소규모로 사용하기에는 부담이 있다.

www.bearpooh.com


Jenkins의 SSH Agent 컨테이너의 Dockerfile과 Anaconda를 활용하여 리눅스 기반의 파이썬 빌드 에이전트를 생성한다.
생성한 빌드 에이전트는 SSH 통신을 이용하여 Jenkins에 에이전트로 등록한다.

진행 순서는 다음과 같다.

  • Jenkins SSH 에이전트 이미지 생성 Dockerfile 작성
  • Dockerfile 빌드에 필요한 외부 파일 다운로드와 폴더 구성
  • Jenkins 에이전트 이미지 빌드와 배포

 

 

Jenkins SSH 에이전트 이미지 생성 Dockerfile 작성

Jenkins에 연결할 Python 기반의 에이전트를 생성하는 Dockerfile을 작성한다.

Jenkins에서 ssh-agent Docker 이미지를 제공한다.

 

Docker Hub

 

hub.docker.com


GitHub에 공개 된 소스코드는 다음과 같다.

 

GitHub - jenkinsci/docker-ssh-agent: Docker image for Jenkins agents connected over SSH

Docker image for Jenkins agents connected over SSH - GitHub - jenkinsci/docker-ssh-agent: Docker image for Jenkins agents connected over SSH

github.com


ssh-agent의 latest 이미지를 사용하면 되는데 몇 가지 문제가 있다.

  • ssh-agent 이미지의 베이스 이미지인 openjdk:8-jdk-buster가 Debian 리눅스를 사용한다.
  • ssh-agent 이미지를 베이스로 다음 이미지를 생성하면 Entrypoint인 setup-sshd가 정상 동작하지 않는다.
  • 기본 ssh-agent 컨테이너에 Anaconda를 설치한 이미지를 생성하면, SSH 키 설정으로 인해 다른 곳에서 활용하기 어렵다.


이러한 이유로 ssh-agent의 Dockerfile 자체를 수정해서 사용한다.
openjdk:8-jdk-buster를 베이스로 하는 ssh-agent의 Dockerfile 경로는 다음과 같다.
https://github.com/jenkinsci/docker-ssh-agent/blob/master/8/debian/buster/Dockerfile

해당 Dockerfile 중간에 필요한 프로그램을 설치하고, 최종적으로 setup-sshd가 실행되도록 구성한다.
ssh-agent의 Dockerfile은 MIT 라이선스이므로 라이선스 명시만 유지하면 자유롭게 코드 수정이 가능하다.

 

python 저장소 설정 파일과 Anaconda 설치 파일 복사

Dockerfile의 35번 라인에 아래 코드를 추가한다.

## 에이전트의 파이썬 설정파일과 Anaconda 설치파일을 복사한다. 
# COPY ./data/python_conf/etc/pip.conf /etc/ 
# COPY ./data/python_conf/home/jenkins/.condarc /home/jenkins/ 
# COPY ./data/python_conf/home/jenkins/.pydistutils.cfg /home/jenkins/ 
# COPY ./data/python_conf/home/jenkins/.pypirc /home/jenkins/ 
COPY ./data/python_conf / 
RUN chown ${user}:${group} ${JENKINS_AGENT_HOME}/.condarc \
    ${JENKINS_AGENT_HOME}/.pydistutils.cfg \
    ${JENKINS_AGENT_HOME}/.pypirc

## anaconda 설치 파일을 복사한다. 
# COPY ./data/anaconda_install/home/jenkins/Anaconda3-2021.05-Linux-x86_64.sh / 
COPY ./data/anaconda_install /

이후 해당 파일들을 폴더 구조에 맞게 재배치 할 것이다.

 

참고로, .condarc, .pydistutils.cfg, .pypirc 파일들은 root 계정으로 복사하기 때문에 소유자와 그룹이 root:root이다.

나중에 Jenkins에서 접근할때에는 jenkins 계정을 사용하므로, 소유자와 그룹을 jenkins:jenkins로 변경한다.

 

sudo, build-essential, locales, vim 설치

apt-get 명령어 부분 (37~39번 라인)을 다음과 같이 수정한다.

# 수정 전 
RUN apt-get update \ 
  && apt-get install --no-install-recommends -y openssh-server \ 
  && rm -rf /var/lib/apt/lists/* 
  
# 수정 후 
RUN apt-get update \
    && apt-get install --no-install-recommends -y openssh-server \
    && apt-get install sudo build-essential locales vim -y \
    && rm -rf /var/lib/apt/lists/* \
    && rm /etc/localtime \
    && ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime


사용 목적은 다음과 같다.

  • sudo - jenkins 계정에 관리자 권한을 부여
  • build-essential - 소스코드 빌드 시 필요한 기본적인 패키지 설치 (gcc, g++, make, perl, 라이브러리 등)
  • locales - 시간 정보를 서울로 변경
  • vim - 파일 수정을 위한 편집기 

 

jenkins 계정 권한 부여와 Anaconda 설치

sshd 설정 코드 (40번 라인) 전에 아래 코드들을 추가한다.

RUN adduser ${user} sudo \ 
  && echo "%sudo ALL=(ALL) NOPASSWD:ALL" >> /etc/sudeoers \ 
  && chmod a+rwx ${JENKINS_AGENT_HOME} ENV PATH /opt/anaconda3/bin:$PATH 
  
## anaconda 설치 및 가상환경 세팅 
RUN bash /home/jenkins/Anaconda3-2021.05-Linux-x86_64.sh -b -p /opt/anaconda3 \
    && \rm /home/jenkins/Anaconda3-2021.05-Linux-x86_64.sh \
    && /opt/anaconda3/bin/conda update conda \
    && /opt/anaconda3/bin/conda update anaconda \
    && /opt/anaconda3/bin/conda update --all \
    && /opt/anaconda3/bin/conda init bash \
    && /bin/bash -c "source /root/.bashrc" \
    && /opt/anaconda3/bin/conda create -y -n dist_py27 python=2.7 \
    && /opt/anaconda3/bin/conda create -y -n dist_py36 python=3.6

USER ${user}

RUN /opt/anaconda3/bin/conda init bash \
    && /bin/bash -c "source ${JENKINS_AGENT_HOME}/.bashrc" 

USER root


jenkins 계정에 sudo 권한을 부여하고 Anaconda를 설치한다.

  • jenkins 계정에 sudo 권한을 부여
  • Anaconda 실행 파일 경로를 PATH 환경 변수에 추가
  • Anaconda 설치, 업데이트, 빌드를 위한 가상환경 생성
  • jenkins 계정으로 전환하고 Anaconda 초기화
  • 이후 셋팅 과정은 root 계정으로 진행되어야 하므로 root 계정으로 전환

 

 

setup-sshd 파일 실행 권한 부여

setup-sshd 복사 명령 (51번 라인) 아래에 다음 코드를 추가한다.

ENV PATH /usr/local/bin:$PATH RUN chmod +x /usr/local/bin/setup-sshd


Dockerfile에는 setup-sshd 파일을 복사하고 실행하도록 되어 있다.
github에서 해당 파일을 다운 받고 파이썬 저장소 설정 파일처럼 폴더 구조에 맞게 재배치 할 것이다.

최종 코드

Dockerfile을 수정한 최종 코드는 다음과 같다.

# The MIT License
#
#  Copyright (c) 2015, CloudBees, Inc.
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.

FROM openjdk:8-jdk-buster

ARG user=jenkins
ARG group=jenkins
ARG uid=1000
ARG gid=1000
ARG JENKINS_AGENT_HOME=/home/${user}

ENV JENKINS_AGENT_HOME ${JENKINS_AGENT_HOME}

RUN groupadd -g ${gid} ${group} \
    && useradd -d "${JENKINS_AGENT_HOME}" -u "${uid}" -g "${gid}" -m -s /bin/bash "${user}"

## 에이전트의 파이썬 설정파일과 Anaconda 설치파일을 복사한다.
# COPY ./data/python_conf/etc/pip.conf /etc/
# COPY ./data/python_conf/home/jenkins/.condarc /home/jenkins/
# COPY ./data/python_conf/home/jenkins/.pydistutils.cfg /home/jenkins/
# COPY ./data/python_conf/home/jenkins/.pypirc /home/jenkins/
COPY ./data/python_conf /
RUN chown ${user}:${group} ${JENKINS_AGENT_HOME}/.condarc \
    ${JENKINS_AGENT_HOME}/.pydistutils.cfg \
    ${JENKINS_AGENT_HOME}/.pypirc

## anaconda 설치 파일을 복사한다.
# COPY ./data/anaconda_install/home/jenkins/Anaconda3-2021.05-Linux-x86_64.sh /
COPY ./data/anaconda_install /

## 필요한 apt package 목록들을 install한다.
# setup SSH server
RUN apt-get update \
    && apt-get install --no-install-recommends -y openssh-server \
    && apt-get install sudo build-essential locales vim -y \
    && rm -rf /var/lib/apt/lists/* \
    && rm /etc/localtime \
    && ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

RUN adduser ${user} sudo \
    && echo "%sudo ALL=(ALL) NOPASSWD:ALL" >> /etc/sudeoers \
    && chmod a+rwx ${JENKINS_AGENT_HOME}

ENV PATH /opt/anaconda3/bin:$PATH

## anaconda 설치 및 가상환경 세팅
# RUN chmod +x /home/jenkins/Anaconda3-2021.05-Linux-x86_64.sh \
RUN bash /home/jenkins/Anaconda3-2021.05-Linux-x86_64.sh -b -p /opt/anaconda3 \
    && \rm /home/jenkins/Anaconda3-2021.05-Linux-x86_64.sh \
    && /opt/anaconda3/bin/conda update conda \
    && /opt/anaconda3/bin/conda update anaconda \
    && /opt/anaconda3/bin/conda update --all \
    && /opt/anaconda3/bin/conda init bash \
    && /bin/bash -c "source /root/.bashrc" \
    && /opt/anaconda3/bin/conda create -y -n dist_py27 python=2.7 \
    && /opt/anaconda3/bin/conda create -y -n dist_py36 python=3.6

USER ${user}

RUN /opt/anaconda3/bin/conda init bash \
    && /bin/bash -c "source ${JENKINS_AGENT_HOME}/.bashrc" 

USER root

RUN sed -i /etc/ssh/sshd_config \
        -e 's/#PermitRootLogin.*/PermitRootLogin no/' \
        -e 's/#RSAAuthentication.*/RSAAuthentication yes/'  \
        -e 's/#PasswordAuthentication.*/PasswordAuthentication no/' \
        -e 's/#SyslogFacility.*/SyslogFacility AUTH/' \
        -e 's/#LogLevel.*/LogLevel INFO/' && \
    mkdir /var/run/sshd

VOLUME "${JENKINS_AGENT_HOME}" "/tmp" "/run" "/var/run"
WORKDIR "${JENKINS_AGENT_HOME}"

COPY setup-sshd /usr/local/bin/setup-sshd
ENV PATH /usr/local/bin:$PATH
RUN chmod +x /usr/local/bin/setup-sshd

EXPOSE 22

ENTRYPOINT ["setup-sshd"]

 

 

Dockerfile 빌드에 필요한 외부 파일 다운로드와 폴더 구성

Dockerfile 빌드에 필요한 외부 파일들을 다운로드하고, Dockerfile 코드에 맞게 폴더를 구성한다.

Anaconda 설치 파일 다운로드

아래 사이트에 접속하여 Anaconda 설치 파일을 다운로드한다.

 

Anaconda | Individual Edition

Anaconda's open-source Individual Edition is the easiest way to perform Python/R data science and machine learning on a single machine.

www.anaconda.com


다운로드 링크가 접속한 PC의 OS에 맞춰 나온다. 리눅스 버전을 사용할 것이라 다운로드 링크 하단의 펭귄을 클릭한다.


우측의 Linux 부분에서 64-Bit (x86) Installer를 클릭하고 다운로드한다.


현재 배포판은 2021.05 버전으로 다운로드 링크는 다음과 같다.
https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-x86_64.sh

 

Anaconda, 파이썬 저장소 변경 파일 준비

Anaconda 저장소 설정 파일인 .condarc와 파이썬 저장소 설정 파일인 pip.conf, .pydistutils.cfg, .pypirc 을 준비한다.
기존에 설정한 리눅스 기반 아나콘다 환경이 있으면 파일을 복사하면 되고, 없으면 새로 작성한다.

.condarc
Anaconda의 저장소 설정 파일이다.
아래 포스팅의 'Conda 클라이언트 설정 - 리눅스' 부분을 참고하여 작성한다.

 

Nexus3를 이용한 Conda 사설 저장소 구축

Conda 저장소는 데이터 과학과 머신러닝, 딥러닝에 주로 사용하는 아나콘다 패키지의 공식 저장소이다. Nexus3를 이용한 Conda 사설 저장소 구축은 1개 저장소만 필요하다. proxy (Remote) - 외부의 Conda

www.bearpooh.com


pip.conf
Python의 pip 설치를 위한 저장소 설정 파일이다.
아래 포스팅의 'pip 클라이언트 설정 - 리눅스' 부분을 참고하여 작성한다.

 

Nexus3를 이용한 PyPi 사설 저장소 구축

Nexus3를 이용한 PyPi 사설 저장소 구축은 3개의 저장소가 필요하다. hosted (Local) - 내부에서 작성한 Python 패키지인 Wheel (Whl) 파일을 배포한다. proxy (Remote) - 외부의 PyPi 저장소의 패키지를 저장하고..

www.bearpooh.com


.pydistutils.cfg
Python의 Easy Install을 위한 설정이다.
Nexus3에 PyPi 저장소를 구성한 경우 다음 템플릿을 활용하여 작성한다.

 

[easy_install]
index_url = Nexus3_주소:포트/repository/pypi-repos/simple


NEXUS3_주소 에 http:// 또는 https:// 가 포함되어야 한다.

PyPi 기본 경로를 사용하는 경우 index_url의 값을 https://pypi.org/simple로 변경한다.
jFrog 같은 다른 저장소를 사용하는 경우 설정한 주소를 입력한다.

Easy Install 관련 내용은 다음 포스팅을 참고한다.

 

윈도우 환경에서 파이썬의 easy_install, pip 사용하기

파이썬의 경우 활용할 수 있는 라이브러리가 무궁무진합니다. 보통 GitHub나 라이브러리를 제공하는 사이트에서 다운로드 해서 직접 Install 하는 방법으로 활용할 수 있습니다. 그러나 Python의 라

www.bearpooh.com


.pypirc
작성한 Python 패키지의 로컬 배포를 위한 설정이다.
Nexus3에 PyPi 저장소를 구성한 경우 다음 템플릿을 활용하여 작성한다.

 

[distutils]
index-servers = local
[local]
repository: NEXUS3_주소:포트/repository/pypi-local/
username:Nexus3_사용자아이디
password:Nexus3_패스워드입력


Nexus3에 사용하려는 계정이 생성되어 있어야 하고, 해당 저장소에 대한 권한 (읽기, 쓰기)이 부여되어야 한다.

PyPi 기본 저장소를 사용하는 경우 아래 포스팅을 참고한다.

 

파이썬(Python) PyPI 배포하기

오랜만에 다시 주말코딩을 시작해보았습니다. 2020년 목표 중에 주말코딩이 목표 중에 하나였는데... 생각보다 ㅎㅎ 역시 쉽지 않더라구요. 역시 세상엔 재밌는 것들이 너무 많죠. ㅋㅋㅋ 하지만

hanminwoo.com


jFrog 같은 다른 저장소를 사용하는 경우 설정한 주소를 입력한다.

 

 

Jenkins SSH 에이전트의 SSH 설정을 위한 setup-sshd 준비

Dockerfile에서 최종적으로 실행하는 setup-sshd 파일을 다운로드한다.

경로는 다음과 같다.
https://github.com/jenkinsci/docker-ssh-agent/blob/master/setup-sshd

해당 프로젝트를 Clone해도 되고, Zip으로 다운로드해도 되고, 코드 전체를 복사해서 새로운 파일로 생성해도 된다.

Docker 이미지 빌드에 사용할 파일과 폴더 구조 정리

위의 파일들이 모두 준비되었다면 준비 된 파일들은 다음과 같다.

  • Anaconda 설치 파일
  • .condarc
  • pip.conf, .pydistutils.cfg, .pypirc
  • setup-sshd


해당 파일들을 Dockerfile에 정의한 것과 동일한 구조로 다음과 같이 정리한다.

Dockerfile
setup-sshd
\data
    \python_conf
        \home\jenkins
            \.condarc
            \.pydistutils.cfg
            \.pypirc
        \etc
            \pip.conf
    \anaconda_install\home\jenkins
        \Anaconda3-2021.05-Linux-x86_64.sh

 

 

Jenkins 에이전트 이미지 빌드와 배포

이제 모든 준비를 마쳤으므로 이미지 빌드와 배포를 진행한다.

배포는 로컬에 구성한 Docker 저장소에 진행한다.
로컬 Docker 저장소 구축은 다음 포스팅을 참고한다.

 

Nexus3를 이용한 Docker 사설 저장소 구축

Nexus3를 이용한 Docker 사설 저장소 구축은 3개의 저장소가 필요하다. hosted (Local) - 내부에서 생성한 Docker 이미지 파일을 배포 (Push)한다. proxy (Remote) - 외부의 Docker 저장소의 이미지들을 저장하고..

www.bearpooh.com


dockerhub에 배포하는 경우 회원 가입과 개인 저장소 생성을 진행해야 한다. 아래 포스팅을 참고한다.

 

(Docker)도커 - (Docker Hub) 도커 허브 사이트에 저장(push) 및 가져오기(pull)

(Docker)도커 - (Docker Hub) 도커 허브 사이트에 저장(push) 및 가져오기(pull) 도커 이미지를 저장하고, 다른 호스트에서 가져다가 사용하는 방법에는 3가지 방법이 있습니다.  docker save 명령어로

reddb.tistory.com

 

Jenkins 에이전트 이미지 빌드

Dockerfile이 위치하는 경로로 이동하고 아래 명령을 실행하여 Docker 이미지를 빌드한다.

$ docker build --tag jenkins-agent-python:1.0.0 .



생성 된 이미지가 정상적으로 컨테이너를 생성하는지 확인한다.

$ docker run -d --name python-agent01 \
  -v 공유폴더경로:/home/jenkins_data jenkins-agent-python:1.0.0 
$ docker exec -it python-agent01 /bin/bash 
$ docker stop python-agent01 
$ docker rm python-agent01

 

 

Jenkins 에이전트 이미지 배포

생성 된 Docker 이미지를 배포하기 전에 배포를 위한 Tag를 지정한다.

최초 버전이므로 1.0.0으로 지정하고, latest도 지정한다.
Nexus에 구성한 경우 Docker의 hosted (Local) 저장소 포트를 지정한다.

$ docker tag jenkins-agent-python:1.0.0 \
  Docker_저장소_주소:포트/프로젝트명/jenkins-agent-python:1.0.0 

$ docker tag jenkins-agent-python:1.0.0 \
  Docker_저장소_주소:포트/프로젝트명/jenkins-agent-python:latest


태그 지정이 완료되면 Docker 저장소에 Push한다.
이미지 크기가 약 5~6 GB 정도 되기 때문에 오래 걸린다. 가급적 유선 네트워크에서 진행하는 것을 권장한다.

$ docker push Docker_저장소_주소:포트/프로젝트명/jenkins-agent-python:1.0.0 
$ docker push Docker_저장소_주소:포트/프로젝트명/jenkins-agent-python:latest