블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

Apt.ly를 이용한 데비안 리포지토리 생성


조대협 (http://bcho.tistory.com)




앞의 글에서 Jenkins + Maven 조합을 통해서 애플리케이션 설치 파일을 데비안 패키지로 패키징하는 방법에 대해서 알아보았다. 이제 이 패키지를 서버에 설치하는 방법을 살펴본다.

패키지를 설치하는 방법은 간단하게 데비안 패키지 파일을 설치하고자 하는 서버에 복사해놓은 다음에, sudo apt-get install을 이용해서 설치하는 방법도 있지만, 설치하고자 하는 서버마다 복사하기가 번거롭기 때문에 조금 더 쉬운 접근을 위해서 데비안 패키지 서버를 올리는 방법이 있다. 우리가 JDK나  node.js 등 다양한 유닉스 패키지를 apt-get 을 이용하여 설치가 가능한것은 미리 데비안 패키지 리파지토리 서버가 지정되어 있고, 그 서버내에 패키지들이 등록되어 있기 때문인데, 애플리케이션 패키지를 같은 방법으로 설치할 수 있게 하려면 애플리케이션 데비안 패키지 파일을 등록할 리포지토리 서버를 설정하면 된다.


지금까지 구현해온 파이프라인은 아래 그림과 같다

  1.  gitHub 로 부터 Jenkins가 자바 코드를 자바 코드를 당겨온다

  2. 이 코드를 Maven을 이용하여 빌드한다

  3. Maven은 코드 빌드가 끝나고 이를 데비안 패키지로 패키징 한다.

  4. Jenkins는 데비안 패키징 파일을 로컬 리포지토리인 apt.ly에 저장한다.

  5. Spinnaker에서 설치할때 데비안 패키지를 apt.ly에서 당겨서 설치한다.


앞의 글에서 까지 1,2,3과정까지 진행을 하였고, 이 글에서는 4번 과정을 구현할 예정이다.

다양한 오픈소스가 있지만, 플랫폼 종속성이 없고 손쉽게 설치가 가능한 apt.ly (www.aptly.info) 를 기준으로 설명을 하고자 한다.


apt.ly 설치

여기서 설명하는 설치는 데비안 리눅스 9을 기준으로 하여 설명한다.

설치는 앞의 글에서 설치한 Jenkins 서버에 그대로 설치하도록 한다.

설치 방법은 간단하다. www.aptly.info 사이트에서 설치 메뉴얼을 체크하여, 현재 사용하는 리눅스 버전에 맞는 바이너리를 wget을 이용해서 다운 로드 받은 후에, chmod +x 로 실행 권한만 주면 된다.


$ wget https://dl.bintray.com/smira/aptly/0.9.5/debian-squeeze-x64/aptly

$ chmod +x aptly


명령어가 설치 되었으면 리파지토리를 생성해야 한다.

리포지토리 생성 과 확인

리포지 토리 생성은 aptly repo crete {리포지토리 명} 을 입력하면 된다.  아래 명령은 “terry-repo”라는 이름의 리포지토리를 생성한것이다.

%./aptly repo create terry-repo


아래 명령은 terry-repo 라는 리포지토리에 대한 정보를 조회 하는 명령이다.

%./aptly repo show -with-packages terry-repo


아래는 실제 실행결과 인데, 테스트를 위해서 helloterry_1.0_all 이라는 패키지를 등록해놨기 때문에 하나의 패키지가 등록되서 보이는 것을 확인할 수 있다.



apt.ly 에 패키지 등록하기

리포지토리가 생성되었으면, maven 에서 빌드한 패키지를 apt.ly 리포지토리에 등록해보자

등록하는 방법은 aptly repo add -force-replace {리포지토리명} {데비안 패키지 파일명} 식으로 사용하면 된다.

아래는 terry-repo에 helloworld.deb 파일을 등록하는 명령이다.

%./aptly repo add -force-replace terry-repo helloworld.deb

apt.ly 리포지토리 퍼블리슁하기

패키지를 등록했으면 외부에서 억세스사 가능하도록 리포지토리 퍼블리쉬를 해야 하는데, 퍼블리쉬는 어떤 버전의 OS와 CPU 타입에 설치할 수 있는지등의 메타 정보를 함께 등록한다.

명령어 사용법은 aptly publish repo -distribution=”{OS 버전 정보}" -architecture=”{CPU 타입}” -skip-signing=true {리포지토리명}

식으로 사용한다.

원래 데비안 패키지를 외부로 배포를 할때는 패키지의 변경(원하지 않은)을 막기 위해서 패키지에 사이닝을 하는데, 여기서는 -skip-signing 을 이용하여 사이닝 단계를 건너뛰도록 하였다. 이 리파지토리는 외부에서 억세스하는 용도가 아니라 내부에서 CI/CD 파이프라인 단계에서만 사용되기 때문에 사이닝을 생략하였다.


아래 명령은 데비안 stretch 버전에 amd64 (intel CPU)에 terry-repo 이름으 리포지토리를 퍼블리슁한것이다.

%./aptly publish repo -distribution=stretch -architectures="amd64" -skip-signing=true terry-repo


apt.ly 서버 기동

퍼블리슁이 되었다고 당장 리포지토리를 접근 가능한것이 아니다. apt-get을 이용한 인스톨은 HTTP 프로토콜을 이용해서 접근하기 때문에 apt.ly 파일 저장소를 접근 가능하게 하는 웹서버를 올려야 한다.

간단한 방법으로는 aptly serve 명령어를 이용해서 웹서버를 올리는 방법이 있다.

아래 명령어 처럼 aptly serve -listen={IP:포트}를 적으면 된다.


% ./aptly serve -listen=:9090 > aptly.log &


이 보다는 제대로 서비스를 하기위해서는 웹서버에 올리는게 좋은데,

(참고 : https://www.spinnaker.io/guides/tutorials/codelabs/hello-deployment/)

% sudo apt-get install nginx

를 통해서 nginx 를 설치한 후에, /etc/nginx/sites-enabled/default 파일을 다음과 같이 편집한다.


server {
       listen 9999 default_server;
       listen [::]:9999 default_server ipv6only=on;
       root /var/lib/jenkins/.aptly/public;
       index index.html index.htm;
       server_name localhost;
       location / {
               try_files $uri $uri/ =404;
       }
}


이때 root에 aptly의 public 디렉토리를 명시해줘야 하는데, aptly를 설치한 디렉토리의 .aptly/public 이 되는게 일반적이다. 여기서는 /var/lib/jenkins 디렉토리 아래에 리포지토리를 만들었기 때문에 /var/lib/jenkins/.aptly/public 디렉토리를 홈 디렉토리로 설정하였다.


nginx 를 기동하면 http 9999번 포트로 데비안 패키지 서비스를 시작한다.

apt.ly 를 통한 패키지 설치

데비안 패키지 서버를 설치하고 패키지를 등록했으면 실제로 패키지를 다른 서버에서 인스톨 해보자

다른 서버에서 이 패키지 서버에 대한 정보를 알고 있어야 하는데 (서버 주소) 이 정보는 /etc/apt/sources.list 라는 파일에 아래와 같은 형태로 등록 되어 있다.


deb http://deb.debian.org/debian/ stretch main

deb-src http://deb.debian.org/debian/ stretch main

deb http://security.debian.org/ stretch/updates main

deb-src http://security.debian.org/ stretch/updates main

deb http://deb.debian.org/debian/ stretch-updates main

deb-src http://deb.debian.org/debian/ stretch-updates main


이 파일에 앞서 설정한 데비안 리포지토리 서버 (apt.ly) 서버의 주소와 정보를 입력해주면 된다.

만약 http://myserver-ip:9999 포트로 서버를 올렸다면 아래와 같은 정보를 /etc/apt/sources.list 에 추가해주면 된다.


deb http://myserver-ip:9999 stretch main


설정이 끝났으면

%sudo apt-get update

명령을 실행하면 아래와 같이 새로운 리포지토리에서 정보를 읽어오는 것을 확인할 수 있다.


모든 준비가 끝났다.

인스톤을 해보자. 인스톨은 sudo apt-get install을 이용하면 된다.

앞서 등록한 패키지 명이 helloterry 였기 때문에 간단하게 아래와 같이 sudo apt-get install helloterry 명령어를 실행하면 된다.



이외에도 유사한 툴로 pulp (https://docs.pulpproject.org/user-guide/introduction.html#what-pulp-can-do)

클라우드 서비스로는 cloudsmith.io (https://cloudsmith.io/)등이 있다. 

작은 규모의 팀이라면 관리 문제도 있으니 클라우드 서비스를 쓰는 것도 좋은 방안이 되지 않을까 한다.



Maven으로 데비안 패키지를 만들어보자


(http://bcho.tistory.com)

조대협

애플리케이션 배포

CI/CD 빌드 배포 프로세스에서, 컴파일된 애플리케이션을 배포하는 방법은 여러가지가 있다. 빌드된 바이너리를 Ansible과 같은 Configuration management 도구를 이용해서 배포하는 방법이 일반적이지만, 작업이 복잡한 경우에는 많은 스크립트 작업이 필요한 경우가 있다.

보통 애플리케이션 배포는 단순하게 바이너리만을 복사하는 것이 아니라, 이에 필요한 의존성이 있는 패키지 (예를 들어 JDK나 기타 의존되는 라이브러리)를 배포해야 하는 경우도 있고, 경우에 따라서는 의존되는 파일이나 복잡한 디렉토리 구조를 생성해야 하는 경우가 있다. 이를 Ansible과 같은 Configuration management 툴을 사용하게 되면 스크립트가 복잡해질 수 있는데, Debian 패키지 (apt-get install 로 설치하는)로 패키징을 하면, 의존성이 있는 패키지나, 복잡한 디렉토리 구조 설정, 그리고 여러 파일 설치를 한번에 끝낼 수 있다.

데비안 패키지 파일 생성

디렉토리 구조

데비안 패키지 생성은 어렵지 않다. 먼저 데비안 패키지 파일에 패키징할 파일을 저장한 “작업 디렉토리"를 하나 만든다. 그리고 그 아래 “홈 디렉토리”에 설치될 경로와 파일을 저장한다.

예를 들어 “홈 디렉토리”가 “/home/terrycho”면 이 패키지를 설치하는 시스템에 /home/terrycho라는 디렉토리가 생성이되고 “작업 디렉토리"아래에 /home/terrycho/my.jar 라는 파일이 있으면 대상 시스템에도 같은 경로에 파일이 설치된다.

파일 구조

패키지에 대한 정보를 설정하기 위해서는 “작업 디렉토리” 아래에 “/DEBIAN” 디렉토리 안에 각종 설정 파일을 넣어둘 수 있는데, control 이라는 파일은 필수로 필요한 파일이다. 이 파일에는 데비안 패키지의 필수 정보인 패키지명, 정보들이 들어간다.  아래는 샘플 내용이다.


Package: ${build.finalName}

Version: ${project.version}

Section: misc

Priority: low

Architecture: all

Depends: oracle-java8-installer | openjdk-8-jre

Description: spinnaker spring test

Maintainer: {my email}


각 항목을 살펴보자

  • Package : 가장 중요한 항목으로 패키지 명을 정의한다. apt-get install 시, 이 패키지명으로 지정해서 인스톨을 한다.

  • Version : 패키지 버전이다. 설치된 패키지를 업그레이드할때 이 버전을 비교하기 때문에 매우 중요한 필드 이다. 버전이 같으면 내용이 다르더라도 업데이트가 되지 않으니 주의가 필요하다.

  • Section : 패키지의 분류인데, 크게 중요하지는 않다.

  • Architecture : 설치 가능한 CPU 플랫폼 종류를 정의한다.

  • Depends : 이 패키지를 실행하기 위해서 필요한 다른 패키지명을 리스팅 한다. 예를 들어 자바 애플리케이션의 경우 JDK를 설치하도록 할 수 있다. 위의 예제는 oracle-java8이나, openjdk-8 런타임을 설치하도록 정의되어 있다.

  • Description : 패키지에 대한 설명을 적는다.

  • Maintainer : 패키지를 관리하는 개발자 이메일을 적는다.


control 파일 이외에도 추가 설정 파일을 통해서 인스톨전 후의 추가 작업을 preinstall이나, postinstall 스크립트를 지정할 수 있다.

패키지를 만들어보자

대략적인 개념을 이해 했으면 실제로 패키지를 만들어보자

아래와 같이 hellodebian 디렉토리에 hello.txt와 control 파일을 생성하였다.


/home/terrycho/hellodebian/home/hello.txt

/home/terrycho/hellodebian/DEBIAN/control


hello.txt 는 간단한 텍스트 내용이 들어있는 파일이고, control 파일의 내용은 다음과 같다.


Package: hellodebian

Version: 1.0

Section: misc

Priority: low

Architecture: all

Depends: oracle-java8-installer | openjdk-8-jre

Description: spinnaker spring test

Maintainer: {my email}


이 디렉토리를 패키지로 묶으려면 “dpkg-deb --build {작업 디렉토리명}” 명령어를 실행하면 된다.



위와 같이 명령을 실행하면 hellodebian.deb 파일이 생성된다.

설치 확인은

% sudo apt-get install ./hellodebian.deb

명령을 실행하면 설치가되는 것을 확인할 수 있고, 의존성에 정의한 Jre가 같이 설치되는것을 확인할 수 있다.




Maven을 이용한 데비안 패키지 파일 생성

그러면 실제 애플리케이션 빌딩 과정에서 이렇게 디렉토리를 구조를 정의하고 dpkg 명령어를 사용해서 패키징을 해야 하는가? 다행이도 언어마다 빌드 스크립트에 데비안 패키지로 패키징을 해줄 수 있는 플러그인이 있다.

여기서는 자바 빌드를 위한 maven에서 데비안 패키지를 묶어주는 jdeb 플러그인에 대해서 알아보자. (https://github.com/tcurdt/jdeb)

아래는 jdeb을 사용하는 pom.xml이다.


   <build>

       <plugins>

           <plugin>

               <groupId>org.springframework.boot</groupId>

               <artifactId>spring-boot-maven-plugin</artifactId>

           </plugin>

           <plugin>

               <artifactId>jdeb</artifactId>

               <groupId>org.vafer</groupId>

               <version>1.5</version>

               <executions>

                   <execution>

                       <phase>package</phase>

                       <goals>

                           <goal>jdeb</goal>

                       </goals>

                       <configuration>

                           <verbose>true</verbose>

                           <snapshotExpand>true</snapshotExpand>

                           <!-- expand "SNAPSHOT" to what is in the "USER" env variable -->

                           <snapshotEnv>USER</snapshotEnv>

                           <verbose>true</verbose>

                           <controlDir>${basedir}/src/deb/control</controlDir>

                           <dataSet>

                    <data>

                       <src>${project.build.directory}/${build.finalName}.jar</src>

                       <type>file</type>

                       <mapper>

                           <type>perm</type>

                           <prefix>/var/${build.finalName}</prefix>

                           <filemode>755</filemode>

                       </mapper>

                   </data>


                           </dataSet>

                       </configuration>

                   </execution>

               </executions>

           </plugin>

       </plugins>

   </build>



<goal>에 jdeb을 설정하고, <configuration>에 상세 설정 정보를 넣는다.

데비안 패키지는 앞에서 설명 했듯이, control 파일이 필요한데, <controlDir>에 control 파일이 저장되어 있는 디렉토리 위치를 지정한다.

다음으로, <dataSet>에 데비안 패키지에 대한 설정 정보를 지정하는데, 디렉토리 정보등을 정의할 수 있다. <type>file</type>은 파일에 대한 정보를 넣는데, <src>에는 소스 파일을 정의하고 <prefix>에 파일이 저장될 위치를 지정한다. <filemode> 에 Unix file permission을 지정한다.

위의 스크립트는 ${prject.build.directory}/${build.finalName}.jar 파일을 /var/${build.finalName}으로 복사한다.


생성된 jar 파일명은 ${build.finalName}으로 생성되는데, 이 이름은

${artifactId}_{$version}_all 이라는 이름으로 된다.

이 예제에서는 artifactId가 hello-springboot 이고, version은 1.0이기 때문에 최종 생성된 이름은

hello-springboot_1.0_all 로 된다.