

먼저 Jenkins에서 Git을 사용할 수 있는 환경인지 확인해 본다.
Jenkins 관리라는 메뉴로 클릭한 후 두번째 Plugins으로 이동한다. 그 다음에 사용할 수 있는 탭을 확인해 본 다음에 Github 플러그인이 선택되어 있는지 본다.
만약 설치가 안되어 있다고 하면 Github 플러그인을 설치한다.
위 두번째 사진을 보면 Github을 기본적으로 사용할 수 있는 상태가 되어 있는 것을 확인할 수 있다.

cmd창에 docker exec -it jenkins-server bash 를 입력해서 Jenkins 내부에 접속하였다. 접속 후 git-version이라고 입력하면 git의 버전을 출력하면서 git 명령어를 사용할 수 있는지 확인할 수 있다.


Tools(과거: Global Tool Configuration 메뉴)로 이동하여 Git 항목에 가면 기본적으로 쓸 수 있는 Git 명령어가 어떤 것이 있는지도 지정할 수가 있다.
(만약에 Git이 설치가 되어 있지 않다라고 하면 Install Automatically로 설치한다.)
나는 이름을 Default라고 적어주고, Path to Git executable는 git이라고 적은 후 Apply -> Save 하였다.


다음으로 동일한 방식으로 Maven 이라는 빌드 툴도 플러그인을 설치해보자.
마찬가지로 Jenkins 관리-> Plugins 그리고 사용할 수 있는 항목에서 Maven을 선택 한다.
설치 가능 항목에서 Maven을 검색하면 Maven Integration 이라는 메뉴를 확인할 수 있다.
만약에 Maven Integration이 설치 가능 항목에 보이지 않는다고 하면 설치되었는지 설치된 플러그인 목록에서 확인해 봐야 한다.
설치가 다 되었으면 하단에 메이븐 플러그인이 정상적으로 작동했는지 볼 수 있다.

마찬가지로 메이븐이 설치되어 있는지 버전을 한번 확인해보자.
--mvn : 메이븐을 실행할 때는 mvn이라는 단축되어 있는 명령어를 사용한다.
--version 이라고 입력했을 때 버전 표기가 되면 메이븐 설치가 잘 된건데 cannot found라는 오류가 떴다는 얘기는 메이븐이 설치가 안됐다는 이야기이다.


다음에 Jenkins 관리 -> Tools(과거: Global Tool Configuration 메뉴)로 들어가서 조금 전에 했던 Git 설정과 동일하게 진행하면 된다.
거기에서 메이븐 항목에 가서 적절한 이름을 입력하고, 가지고 있는 메이븐을 여기다가 설치를 해주면 되는데 확인한 바 설치가 되어있지 않았다.
그렇기 때문에 Maven이라고 되어있는 항목을 Install Automatically 체크 박스를 선택해주어 설치하였다.
아니면 기존에 가지고 있는 Maven이 있다고 치면 그 Maven의 경로를 입력해줘도 된다.

앞서 Git과 Maven 플러그인 설치를 했는데 Jenkins에서 두 번째 아이템을 만들어서 두 가지 플러그인을 사용해보자.
제일 먼저 아이템의 이름을 My-Second-Item-Project라고 지었다.
이전에 만들었던 프로젝트 타입이 FreeStyle Project였는데 메이븐 플러그인을 설치한 상태에서는 Maven Project를 확인할 수 있다. 그래서 메이븐 프로젝트를 선택하여 만들어 볼 것이다.

다음으로 General 부분 간단한 명령어를 입력한다.
두 번째 소스 코드 관리라고 되어 있는 부분에는 Git에서 코드를 가져와서 컴파일을 해보자.

Pre Stage이라고 되어있는 항목에 가서 메이븐 빌드를 한다.
소스코드를 Github에서 가지고 오게 된다.
그 다음에 해야 될 작업은 메이븐 프로젝트로 만들어진 내용이라 소스코드를 메이븐 빌드 툴로 컴파일을 해 놓아야 한다.
기본적으로 메이븐 관련되어 있는 설정 파일은 pom.xml 이란 파일에 저장을 하도록 되어있다. 그래서 이 pom.xml 파일을 기반으로 해서 메이븐 빌드를 하게 될건데 메이븐 빌드를 할 때 어떤 어떤 항목들에 가지고 빌드할 것인지 지정할 수 있다.
Goals & Options 에다가 clean 다음에 complie 다음에 package 라고 적어주었다.
여기서 clean 이라는 것은 말 그대로 빌드를 기존에 한 것이 있다고 하면 기존에 했었던 빌드를 지우라는 뜻이다. (=새롭게 하겠다는 뜻)
complie은 말 그대로 컴파일 빌드 하겠다는 뜻이고, package라는 것은 컴파일 되어진 내용을 가지고 pom.xml 파일에 지정된 옵션에 따라서 패키지의 파일을 만들라는 뜻이다.
기본적으로 Maven에서는 WAR 파일과 JAR 파일 두가지 형태가 있다.
일반적인 Java Archive 파일과 웹 아플리케이션 형태일 경우에 WAR를 선택할 수 있다.
만약에 만들었던 프로젝트가 Spring Boot로 되어 있는 경우라고 하면, 스프링 부트는 크게 두 가지 형태로 프로그램을 실행할 수가 있다.
첫번째는 웹 어플리케이션일 경우에 실행하고자 하는 어플리케이션 자체가 임베디드 톰캣을 내장하고 있는 형태이다. 톰캣 자체를 프로젝트 내부에 가지고 있다는 뜻이다. 그랬을 경우에는 Jar 파일 형태로 패키징을 했을 때 Jar 파일을 실행하게 되면 내장되어 있는 통켓 서버에 의해서 웹서버가 실행되는 형태이다.
두 번째 방식은 우리가 만들고자 하는 어플리케이션 파일 자체를 웹 어플리케이션 서버에서 사용하는 것이다. 톰캣과 같은 다른 웹 어플리케이션 서버에 우리가 만들었던 패키지 파일을 복사해서 해당하는 서버에 밑에서 운영될 수 있게 선택할 수 있다.
그럴 경우에는 WAR 파일로 패키징을 한 후 패키징 되어있는 WAR 파일을 방금 말씀했던 톰켓이던가 그런 웹 어플리케이션 서버에다가 복사해서 사용하면 된다.
이렇게 pom.xml 파일에 등록되어진 패키징 파일의 형식에 따라서 WAR 파일 또는 Jar 파일로 패키지 해주는 명령어가 제일 마지막에 있는 package라는 옵션이다.
build 옵션을 clean, compile, package라고 적었으므로 clean build를 할 거고, build를 새롭게 시작할 거고, 다음에 지정되어 있는 옵션에 따라서 WAR 파일 또는 Jar 파일 형태로 package 만들겠다는 옵션을 주었다.

참고로 나는 Github에서 가져온 소스코드의 pom.xml을 열어보니 war 파일 형태로 결과가 만들어진다고 나와있다.

여기까지 두 번째 프로젝트 설정이 다 끝나면 Build Now(지금 빌드)를 선택을 한다.


그리고 빌드 중인 것을 클릭한 후 Console Output을 선택하면 콘솔을 확인할 수 있으며 출력이 모두 끝나면 Finished: SUCCESS가 되는지 Fail이 뜨는지 메세지를 확인한다.

최종적으로 빌드가 성공한 다음에는 워크스페이스에 빌드했던 결과물을 확인할 수 있다.
target이라는 폴더 그리고 그 밑에 빌드 파일의 이름이 생성된 것을 확인할 수 있다.
최종적인 파일의 이름은 webapp.war 와 같은 형태로 만들어져 있을 것이다.
이 내용은 github에 터널링으로 접속을 해서 들어간 다음에도 확인할 수 있다.
사진에 빨간 박스를 보면 도커로 기동하고 있는 상태이기 때문에 docker exe command를 입력을 했다. 컨테이너라는 이 중간에 있는 container 명령어를 입력해도 되고 입력하지 않아도 된다.
exec-it 다음에 container id 또는 container name을 입력한 다음에 사용하시고자 하는 쉘의 종류를 선택을 해준다.
그러면 어떤 컨테이너 내부로 접속된 걸 보실 수가 있다. 앱 이라는 wrokspace로 이동을 해주시면 되요.
cd /var/jenkins_home 디렉토리로 들어가면 workspace라는 폴더가 생겨져 있는 것을 확인할 수 있다.
jenkins@b43781784329:/$ cd /var/jenkins_home
jenkins@b43781784329:~$ ls
config.xml nodeMonitors.xml
copy_reference_file.log nodes
fingerprints org.jenkinsci.plugins.gitclient.JGitApacheTool.xml
hudson.model.UpdateCenter.xml org.jenkinsci.plugins.gitclient.JGitTool.xml
hudson.plugins.git.GitTool.xml plugins
hudson.plugins.gradle.Gradle.xml queue.xml
hudson.tasks.Ant.xml queue.xml.bak
hudson.tasks.Maven.xml secret.key
identity.key.enc secret.key.not-so-secret
jenkins.install.InstallUtil.lastExecVersion secrets
jenkins.install.UpgradeWizard.state tools
jenkins.model.JenkinsLocationConfiguration.xml updates
jenkins.mvn.GlobalMavenConfig.xml userContent
jenkins.telemetry.Correlator.xml users
jobs war
logs workspace
jenkins@b43781784329:~$ cd workspace
jenkins@b43781784329:~/workspace$ ls
My-First-Project My-Second-Project
jenkins@b43781784329:~/workspace$ cd My-Second-Project/
jenkins@b43781784329:~/workspace/My-Second-Project$ ls -al
total 24
drwxr-xr-x 5 jenkins jenkins 4096 Apr 2 12:11 .
drwxr-xr-x 4 jenkins jenkins 4096 Apr 2 12:05 ..
drwxr-xr-x 8 jenkins jenkins 4096 Apr 2 12:11 .git
-rw-r--r-- 1 jenkins jenkins 3631 Apr 2 12:11 pom.xml
drwxr-xr-x 4 jenkins jenkins 4096 Apr 2 12:05 src
drwxr-xr-x 10 jenkins jenkins 4096 Apr 2 12:11 target
jenkins@b43781784329:~/workspace/My-Second-Project$ cd target/
jenkins@b43781784329:~/workspace/My-Second-Project/target$ ls -al
total 7880
drwxr-xr-x 10 jenkins jenkins 4096 Apr 2 12:11 .
drwxr-xr-x 5 jenkins jenkins 4096 Apr 2 12:11 ..
drwxr-xr-x 3 jenkins jenkins 4096 Apr 2 12:11 classes
drwxr-xr-x 3 jenkins jenkins 4096 Apr 2 12:11 generated-sources
drwxr-xr-x 3 jenkins jenkins 4096 Apr 2 12:11 generated-test-sources
drwxr-xr-x 4 jenkins jenkins 4096 Apr 2 12:11 hello-world
-rw-r--r-- 1 jenkins jenkins 8025946 Apr 2 12:11 hello-world.war
drwxr-xr-x 2 jenkins jenkins 4096 Apr 2 12:11 maven-archiver
drwxr-xr-x 3 jenkins jenkins 4096 Apr 2 12:11 maven-status
drwxr-xr-x 2 jenkins jenkins 4096 Apr 2 12:11 surefire-reports
drwxr-xr-x 3 jenkins jenkins 4096 Apr 2 12:11 test-classes
jenkins@b43781784329:~/workspace/My-Second-Project/target$
cd /var/jenkins_home 로 이동하여 ls 명령어로 파일 목록을 보면 workspace가 있다.
cd workspace로 이동해 ls 명령어로 확인해보면 이전에 만든 My-First-Project와 My-Second-Project를 확인할 수 있다.
최근에 만든 cd My-Second-Project로 이동하여 ls -al로 파일 목록을 확인해보면 GitHub 레파시토리의 내용들을 다 체크아웃 받은 상태가 보인다.
cd target 이라는 폴더로 이동해 보면 조금 전에 Maven 패키지라는 명령에서 만들어진 최종 War 파일을 확인할 수 있다.
이게 컴파일이 끝난 상태의 최종 빌드 파일이다.
이 빌드 파일을 기존에 있었던 웹 어플리케이션 서버에다가 복사해 넣게 되면 원했던 형태의 샘플 예제가 실행될 것이다.
톰캣 웹 서버를 설치하여 사용자 및 권한, 포트 등 설정사항을 적용하지 않았다면 하단의 링크로 가서 선행하길 바란다.
[DevOps] Tomcat Web Application Server 설치

Jenkins 플러그인 중에서 Tomcat 플러그인을 설치해보자.

기존에 다른 플러그인 관리하는 것과 마찬가지로 Jenkins 관리->Plugins->Available plugins을 선택하게 되면 검색 키워드에다가 deploy 입력했을 때 그림 하단에 있는 항목을 발견할 수 있다.

Deploy to Container라고 되어 있는 플러그인을 설치하자.
이 플러그인이 있어야 Jenkins에서 앞선 시간에 패키징했던 WAR 파일을 Tomcat 웹 어플리케이션 서버에다가 복사를 할 수 있다.

자 이번에도 My-Third-Project 이름의 세번째 프로젝트를 메이븐 프로젝트로 생성해보자.

이때 옵션으로 기존에 있었던 일정한 부분의 설정을 그대로 가지고 와서 확장해서 변경해서 만들 수 있다.
있어요. 예를 들어서 이전에 만든 두번째 프로젝트에서 일정 부분을 가지고 올 거라고 하면 My-Second-Project를 입력해주면 된다.

다음에 간단한 스크립트 입력해준다. 기존에 했던 거랑 유사하지만 이번엔 Tomcat 웹서버에다가 배포하는 것까지 추가하도록 하겠다.
소스 코드 관리의 부분에서 Git을 선택하고, 그 다음에 본인이 쓰고자 하는 레파지토리 주소를 입력해준다.

빌드를 할 때 Maven 빌드를 할 거라고 말했기에 pom.xml 파일을 실행할 것이다. 그러므로 ROOT POM에다가 pom.xml 파일이 입력되어 있는지 확인한다.
두 번째 빌드할 수 있는 옵션에다가 Clean Compile Package라고 입력한다.
다시 한번 설명 하자면 Clean이라는 것은 앞서 빌드되어 있는 내용이 있으면 해당 내용을 지우는 것 즉, 타겟 폴더를 삭제하는 거고, Compile은 말 그대로 빌드, 컴파일 하는 것이고, Package라는 것은 pom.xml 파일에 포함되어 있는 패키징의 형태로 가지고 있는 이 결과물을 압축을 시켜주는 거라고 보면 된다.
Tomcat라는 웹서버에다가 복사를 할거라서 war 파일 형태로 패키징을 하고 있다.

그 다음 중요한게 아래쪽에 있는 Post-build Actions 이라는 부분이다.(=빌드 후 조치)
war file 또는 jar file로 압축이 돼서 파일이 생성된 것까지는 지난 포스트 때 확인 했었다. 여기선 파일이 생성이 됐으면(=post build) 생성된 파일을 가지고 어떤 작업을 할 것이냐 라는 뜻이다.
나는 패키징 되어있는 파일을 컨테이너에 배포를 할 것이다. 그래서 빌드 후 첫 번째 작업으로Deploy war/ear to a contatiner를 선택해준다.

패키징을 만들었던 폴더의 위치에서 어떤 파일을 복사할 것인지 지정을 해야 하는데 그 파일의 이름을 **/*.war로 하였다. 이것은 현재 디렉토리에 있는 파일 그리고 그 하위에 있는 디렉토리를 포함해서 war 파일로 확장자를 가지고 있는 게 대상이라는 뜻이다.

이렇게 빌드 조치에다가 앞에와 같이 항목을 선택한 후 해야 되는 두 번째 작업은 어떠한 컨테이너에다가 배포할 건지 컨테이너를 골라 주어야 한다.

Tomcat 9.x 버전을 선택할 것이다. Tomcat 서버에다가 우리가 만들었던 WAR 파일을 배포하기 위해서는 Tomcat 서버에 접근할 수 있는 즉 Deploy 할 수 있는 권한이 있어야 된다.
Credential이 있어야 되는데 현재 없기 때문에 add라는 메뉴를 클릭하여 새로운 Credential 하나 추가 해야 한다. 추가할 것은 오른쪽 그림에 톰캣 웹서버를 설치를 했을 때 사용할 수 있는 사용자 또는 권한을 추가해주는 메뉴이다.
사용자 권한을 추가했을 때 admin 또는 deployer 또는 tomcat 이런 계정을 만들겠다는 것이다.

이전에 설정한 Tomcat의
tomcat-users.xml에 설정한 내역을 다시 한번 확인해보자.
각각의 계정이 가지고 있는 roles에 이름을 보면 admin 계정 같은 경우에는 manager-gui, manager-script, manager-jmx, manager-status 이렇게 들어가 있고,
deployer 계정 같은 경우에는 manager-script라고 해서 스크립트를 통해서 필요한 톰캣 웹서버에다가 war 파일을 배포하는 권한이 있고,
tomcat 계정은 manager-gui 화면에서 웹상에서 보면서 필요로 하는 배포 작업을 할 수 있게끔 되어 있어있다.

여기선 deployer 계정을 사용할 것이기 때문에 Credential 추가하는 메뉴에서 Username with password 선택해주고, Username에다가 deployer, Password 에다가도 맞게 적어주면 된다.
그 밑에 사용자 ID에 대한 간단한 이름과 그 다음에 Description 지정할 수 있다.
이렇게 Credential을 하나 추가하게 되면 그 다음에 다시 원래 있었던 화면으로 돌아와서 필요로 하는 이 계정 정보를 선택한 다음에 이 WAR 파일 자체를 가지고 서버에 배포할 때 사용할 수 있다.
설정이 끝나면 add를 클릭해준다.

계정을 추가했다면 조금 전에 Tomcat 서버 추가하고 Credential 선택해주는 화면에서 방금 전에 등록했었던 Deploy 계정을 확인할 수 있다.

Deploy 계정을 고른 후 Tomcat 웹 서버가 기동되고 있는 위치(=Tomcat URL)까지 선택을 해준다.
웹서버에 주소를 입력시 여기서 하나 중요한 게 있다. 현재 사용하고 있는 Jenkins는 도커로 기동하며 8080 포트를 이용해서 접속해서 쓰고 있는 상태이다.

위 그림은 앞으로 실행할 화면을 본떠 만든 것이다.
IP주소와 포트번호를 입력하는 부분에서 젠킨스에서 윈도우즈가 가지고 있는 톰캣 서버로 접속을 시도할 때는 윈도우즈의 포트번호를 직접 입력해서 접속을 시도하도록 코너 설정을 해주어야 한다.

명령 프롬프트 창에서 본인 pc의 ip주소를 찾기 위해 ifconfig 명령어를 입력한다.
현재 내 pc에선 ip주소가 172.30.1.45 인 것을 확인할 수 있다.

확인 한 주소를 URL 부분에 적어주고 포트번호 8088로 설정하면 된다.

설정이 다 끝난 다음에 빌드를 실제 실행을 할 것이다.

지금 빌드를 눌러주면 빌드가 되는 것을 왼쪽 하단에서 확인 가능하다.


Console Output을 확인해 보면 빌드 과정이 쭉 보인다. 제일 마지막에 빌드 성공이라는 메시지가 보일 것이다.
그 다음에 체크해야 될 중요한 항목이 하단에 보시는 것처럼 만들었던 이 패키지 파일인 War 파일이 어디에 배포가 되었는지 어디에 복사가 되었는지 확인해보자.


명령프롬프트 창에서 실제 웹 어플리케이션 서버로 이동해 webapps라는 폴더를 확인해보면 압축해서 복사했었던 war 파일이 생긴 것을 확인할 수 있다.

이는 젠킨스에서 war file 압축한 것을 Tomcat 서버로 복사되었다고 볼 수 있다.

hello-world.war파일명과 동일한 형태의 폴더 hello-world가 자동으로 생긴다.

webapps라는 폴더에 정상적인 war 파일을 복사해 놓게 되면 tomcat 웹 서버가 자동으로 인지를 해서 웹 어플리케이션을 실행을 시켜주어 폴더를 확인해보면 압축까지 풀린 것을 확인할 수 있다.

앞에 화면에 나와 있는 것처럼 localhost:8088/manager/html로 이동하면 실제로 만들었던 어플리케이션인 hello-world를 확인해 볼 수가 있다.

실제 hello world라는 폴더로 어플리케이션 이동하기 위해 http://localhost:8088/hello-world 로 url을 입력하였다. (프로젝트 jsp 파일)
잘 나오는 것을 확인할 수 있다.
PollSCM은 폴링 작업을 주기적으로 할 수 있다.
폴링(polling): 하나의 장치(또는 프로그램)이 충돌 회피 또는 동기화 처리 등을 목적으로 다른 장치(또는 프로그램)의 상태를 주기적으로 검사하여 일정한 조건을 만족할 때 송수신 등의 자료처리를 하는 방식
주기적으로 업데이트된 내용을 확인을 해서 빌드를 자동으로 할 수 있는 설정을 해보자.

먼저 기존에 사용하셨던 프로젝트 그대로 가져와 프로젝트 생성(Poject)을 한다.
구성 정보(Configure)에 가서 빌드 트리거(Build Triggers)의 옵션을 추가할 건데 빌드할 수 있는 그 시점에 시간을 명시 할 것이다.
일정한 시간이 되면 자동으로 가지고 오는 작업을 한다던가 아니면 변경된 내용이 있을 때 가지고 온다던가 등 그런 설정을 한번 해 볼 것이다.
이 작업을 하기 위해서 크론잡(cron job)이라는 걸 이용할 것이다.
크론잡(cron job)은 유닉스나 리눅스 계열에서 시간 기반으로 해서 사용할 수 있는 스케줄러이다.
두 가지 설정 방법이 있다.
Build Periodical 설정
코드에 변경사항(업데이트)이 없어도 일단 빌드를 다시 한다.
Poll SCM 설정
업데이트를 해올 때 GitHub에서 데이터를 가지고 올 것이다. 즉, 커밋에 대한 내용이 있을 경우에만 빌드를 다시 한다.

빌드 유발(Build Trigger)에 제일 밑에 보면 두 가지 옵션 중에서 Build periodically 선택하거나 Poll SCM 선택할 수 있다.
변경사항이 있을 때 빌드를 하고 싶으므로 Poll SCM을 선택해주었다.

Schedule에는 분 단위, 시 단위, 일 단위 등 설정을 해주면 된다.

자동으로 업데이트가 된 것을 확인하는 과정을 테스트 해보기 위해 가지고 있는 소스 코드를 변경을 해야한다. 그리고 GitHub에 추가 한다.
추가 후 변경된 사항이 내용이 자동적으로 빌드가 되는지 확인해봐야 한다. 소스코드가 변경이 돼서 커밋까지가 됐다면 위에 세번째 트리거가 실행된 것을 볼 수 있다.
이 세번째 잡은 수동으로 실행한 것이 아니라 이 작업은 Build Now에서 실행된 것이 아니라 트리거에 의해서 자동으로 변경된 커밋을 체크한 다음에 알아서 실행이 됐다고 보면 된다.

로컬 pc에 저장된 프로젝트를 git에 올렸다는 가정하에 로컬에서 프로젝트를 열어 소스 코드가 위치한 곳으로 들어가 내용을 변경해주었다.

git add index.jsp
git commit -m "updated the index.jsp"
git push
다음 명령어를 입력하여 업데이트 내역을 반영해주고, github에 들어가서 변경내역을 확인해준다.

로컬에서 수정한 것이 github에 잘 반영된 것을 확인

이때, 빌드를 실행하지 않았는데도 불구하고 1-2분 뒤 젠킨스에서 자동으로 빌드를 실행하는 것을 확인할 수 있었다.
github에 커밋되어 있는 코드를 자동으로 인지해서 빌드가 된 것이다.
변경한 데이터도 동일한 것을 확인할 수 있다.
추후에는 CD 설정도 하여 실제 서버에 반영되는 것이 리스크가 있다는 점을 고려해 추가 작업을 해줄 필요가 있다.
시작하기에 앞서 DinD 와 DooD에 대해 짧게 정리해보자
둘다 컨테이너 안에서 도커 명령어를 사용하기 위한 방법이다.

docker run --privileged --name dind1 -d docker:20.10.5-dind
docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker

지금까진 로컬 시스템에 있었던 Tomcat에 복사하는 작업만 했었는데, 이제 Jenkins에서 만들어진 결과인 패키징되어 있는 파일을 다른 서버에 복사를 해보자.
결과물 자체를 다른 서버에다가 전달하기 위해서 SSH라는 플러그인 하나 설치를 해야한다.

Jenkins 관리->Plugins를 선택하면 Publish of SSH라는 플러그인을 설치할 수 있다.


Jenkins 관리->System 의 제일 하단으로 내려가면 Publish over SSH 라는 항목이 생긴 것을 확인할 수 있다. 여기서 추가버튼을 눌러준다.
플러그인을 설치하고 접속하려고 하는 SSH 서버에 주소를 입력하면 된다. 서버의 이름 입력하고, 그 다음 서버에 접속할 수 있는 ip address 입력, username 과 passname 까지 입력하자.
그리고 포트번호가 기본적으로 SSH 같은 경우는 22번을 사용하고 있는데 다른 포트로 변경하여 사용도 가능하다. 제일 마지막에 있는 Test Configuration 이라는 버튼을 클릭하면 접속 여부 확인도 가능하다.

이 작업을 위해서 위 사진으로 이해해보자.
제일 먼저 결과물 파일이 위 사진처럼 Jenkins에서 만들어져 있다라고 가정을 해보자.

기존까지는 결과물 파일을 Jenkins에서 만들었으면 Tomcat이라는 서버가 로컬 시스템에 위치하고 있는 상태였다. 그래서 war file을 Jenkins에서 Tomcat 서버에다가 직접 배포하는 과정을 거쳤었다.

이제는 그 과정 대신에 다른 서버에다가 이 결과물 파일을 복사해서 사용을 할 것이다. 이는 로컬 시스템 외에 또 다른 PC가 있어야지만 작업이 가능하다.
그래서 VM을 이용해서 작업을 해도 좋고, 도커에 가상 서버를 설치해도 좋다. 나는 도커에다가 가상의 서버를 하나 설치해서 쓸 것이다.
새롭게 추가되는 도커의 가상 서버 컨테이너에는 일단 ssh 서버가 기동되어 있어야 된다.

복사되어 있는 파일(hello-world.war)을 이러한 방식으로도 운영 가능하다.
예를 들어서 새롭게 만들었던 컨테이너 내부에도 톰캣 서버를 설치를 한다. 그리고 젠킨스에서 war file을 해당하는 서버에 톰캣 폴더에다 복사해서 사용해도 되고,

아니면 톰캣 서버 대신에 새롭게 만들어져 있는 VM 안에 이렇게 도커 엔진을 설치를 한다.
도커 안에 도커가 들어가 있는 것은 좀 특이한 모양이긴 하지만 초록색으로 되어있는 부분이 가상 VM이라 가정을 한다. 그러면 이 안에 포함되어 있는 어떠한 이미지를 이용해서 도커 컨테이너를 갖고 작업을 할 수 있게 된다.
그래서 젠킨스에서 만들어져 있는 war file을 ssh 통해서 해당하는 서버에 복사를 하하고, 도커에서 기동하기 위해서 이미지로 만들어 주어야 한다.

도커에서 말하는 이미지라는 것은 단일화 되어 있는 결과물이다.
실행하고자 하는 내용들이 포함되어 있는 단일화된 결과물인 것이다. 상태를 바꿀 수가 없는 파일이기 때문에 이 내용을 갖고 필요로 하는 인스턴스 즉, 컨테이너를 만들어서 사용하게 되는 것이다.
도커에서 이 이미지를 생성하기 위해서 docker file이라는 것이 필요한데 이 docker file과 조금 전에 복사했었던 이 war file 두 가지가 있어야 이미지가 만들어지는 것이다.
이 이미지에는 tomcat server와 지금 복사가 되어진 war file을 포함하고 있을 것이다.

이제 이 이미지가 있으면 도커 컨테이너 내부에서는 이제 컨테이너를 여러 개 실행할 수 있다. 물론 실습 환경에선 여러 개 실행하지는 않겠지만 위 그림처럼 실행할 수가 있다.
위와 같은 작업은 "Docker in Docker" 방식으로 SSH+Docker 컨테이너를 기동하는 것이다.
젠킨스에선 어떤 작업을 해줘야 할까?
1. 결과 파일을 파일을 ssh서버를 이용해서 복사(서버2)
2. (서버2) Dockerfile + 복사 되어진 *.war -> Docker 이미지 빌드
3. Docker 이미지 -> 컨테이너 생성
젠킨스에서 Publish over SSH 설정이 끝났다는 전제 하에 사용할 SSH Server를 VM으로 띄우기 위한 준비를 해보자.

docker run --privileged --name docker-server -itd -p 10022:22 -p 8081:8080 -e container=docker -v /sys/fs/cgroup:/sys/fs/cgroup edowon0623/docker:latest /usr/sbin/init
도커 컨테이너를 생성 시작하는 명령어이다.
--Privileged : 컨테이너 내부에서 루트 계정을 가지고 실행해야 될 몇몇 명령어들이 있어서 루트 권한을 획득하는 부분
--name docker-server : 컨테이너 이름 지정
-p 10022:22 : 포트포워딩을 설정 -> 컨테이너 내부에 SSH 서버는 22번 포트를 가지고 있지만 로컬 환경에서는 10022라는 포트로 통해서 접속을 시도
edowon0623/docker:latest : 운영체제 환경에 맞춰서 이미지 이름을 구분하여 입력 후 실행

docker ps
도커 프로세스 확인해 보면 정상적으로 도커 서버가 잘 기동이 되어 있는 것을 확인할 수 있다.
하지만 ssh 접속 후 systemctl start docker로 docker를 가동하려고 하면 오류가 발생하는 이슈로 계속 inactive 상태로 유지되었다.
C:\Users\kimmi>ssh root@localhost -p 10022
The authenticity of host '[localhost]:10022 ([::1]:10022)' can't be established.
ECDSA key fingerprint is SHA256:uL37rrYqE7ZXoFj9Ye1VZdAej5EXwJzOjaQwh+KEgfA.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:10022' (ECDSA) to the list of known hosts.
root@localhost's password:
[root@36763f673338 ~]#
[root@36763f673338 ~]# systemctl start docker
A dependency job for docker.service failed. See 'journalctl -xe' for details.
[root@36763f673338 ~]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: inactive (dead)
Docs: https://docs.docker.com
그래서 Windows 환경에서 "Docker in Docker" 방식으로 SSH+Docker 컨테이너가 기동되지 않아 "Docker Out Of Docker" 방식으로 기동해 보았다.
SSH 서버(with 도커 + dood)를 실행하는 명령어는 다음과 같다.

docker run -itd --name docker-server -p 10022:22 -e container=docker --tmpfs /run --tmpfs /tmp -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /var/run/docker.sock:/var/run/docker.sock edowon0623/docker:latest /usr/sbin/init

이전 명령어와의 차이점은 마운트 부분 이외에 새롭게 볼륨 마운트 하나 더 추가가 되어 있다.
바로 호스트 pc에 있는 도커 데몬이 사용하고 있는 도커 소켓과 다음에 우리가 컨테이너 안에서 실행하고자 하는 도커 소켓을 연결 시켜주는 방식이다.

기본적으로 사용하고 있는 호스트 PC는 윈도우 PC이고 여기에 도커 엔진인 도커 데모를 설치해 놓고 사용하고 있다.
그리고 앞선 포스트에서 계속하여 젠킨스를 도커에 설치하여 실행이 되고 있다.
문제가 되었던 부분은 3)번이다. 새로운 도커 컨테이너로 SSH를 통해 Docker가 설치되어 있는 컨테이너를 가동하여 실행하는 방식이었다.
문제는 SSH 접속을 한 다음에 서버에 접속한 상태에서 도커를 가동하기 위한 명령어를 실행할 대 도커 엔진 자체가 가동이 안되는 것이다. 이를 해결하기 위해 도커 컨테이너 자체를 외부에 있는 도커 엔진과 연결시켜서 실행하는 방법을 사용하였다. (=Docker Out Of Docker)
실행하게 되면 기존에 설명한 것처럼 도커 내부에 들어가 필요한 컨테이너를 따로 기동하는 것이 아니라 이미 도커 데스크탑이 기동되어 있는 엔진을 가지고 와서 공유해서 쓰는 방식이기 때문에 그런 문제가 발생하지 않는다.
그래서 이 이후에 이렇게 DOOD 방식으로 실행을 하였을 경우에는 systemctl start docker 등과 같은 명령어를 사용하지 않는다.
다음에 privileged라는 옵션을 사용하지 않는다. 외부에 있는 도코 엔진을 같이 연동해서 사용하는 상태에서는 권한 자체를 루트 권한을 가지고 사용하지 않는다.
즉, 일반적인 도커 컨테이너처럼 사용하면 된다.
마지막으로 앞서 말했듯이 호스트 PC에 있는 도커하고 공유해서 쓰는 것이기 때문에 이미지 명이라든가 컨테이너 명이라든가 볼륨 마운트라든가 포트 같은 것들이 충돌날 수가 있다. 주의하여 사용할 필요가 있다.

SSH로 접속 했을 때 docker 버전 확인 및 Dockerfile 확인 등 도커가 정상가동 되는 것을 확인할 수 있다.
다시 젠킨스로 돌아가 SSH Servers를 세팅해줘야 한다.

SSH Server의 이름은 docker-server라고 써주고, Hostname은 현재 pc의 ip주소를 적어주면 된다.

여기서 주의할 점은 자기 자신이라고 생각하여 localhost라고 적어주면 젠킨스가 자기가 가지고 있는 서버, 자기 자신을 가르키게 되버리기 때문에 꼭 실제 ip 주소를 적어줘야 한다.
Username은 root이고, Remote Directory는 "."으로 찍어주었다. 현재 디렉토리가 루트 디렉토리가 될 수 있도록 만든 것이다.

그리고 고급을 눌러 root의 password를 적어준다 (P@ssw0rd)
포트번호는 SSH 서버 만들 때 10022번으로 만들었기 때문에 10022를 적어준다.

마지막으로 정확한 정보를 기입했는지 확인하기 위해 Test Configuration을 클릭해주면 왼쪽 하단에 Success가 뜨며 제대로 세팅한 것을 알 수 있다. 모든 작업이 끝나면 저장을 눌러준다.
SSH 세팅이 끝났다면 아이템(Item)을 만들어 준다.

Dashboard -> 새로운 Item 으로 이동하여 이름을 My-Docker-Project로 적었다.

그리고 하단에 이전에 만든 My-Third-Project를 복사하여 설정 정보를 그대로 가져온다.

이전에 Poll SCM을 설정했었으나 이번엔 체크를 해제하였다.

빌드 후 조치로 내려가면 이전에 설정했던 Deploy war/ear to a container는 x를 눌러 삭제하도록 하고

대신 Send build artifacts over SSH를 선택해준다.

이름은 위에서 ssh 세팅 해준 docker-server로 적는다.
Transfer Set의 Source files은 어떤 소스 파일을 가지고 서버에 전달할 것인지 지정해줄 수 있는데, targer 폴더 밑에 .war 파일을 가져올 것이기 때문에 targer/*.war라고 적어주었다.
이 상태 그대로 서버에 복사가 되면 target이라는 글자도 그대로 복사가 되어버리기 때문에 Remove prefix에 target 글자를 적어주면 *.war만 복사가 된다.

마지막에 복사될 위치를 지정하는 부분이 있는데 도커 서버의 Remote directory는 "."을 기입한다. 루트로 들어가도록 설정한 것이다.

설정이 완료되면 저장을 하고

아까 전에 접속한 SSH 서버에 현재 디렉토리의 파일을 확인한다.

젠킨스로 돌아와 지금 빌드를 누르고 콘솔을 확인하였을 때 조금 기다리면 Success가 뜨고, war 파일을 지정했던 ssh 서버로 복사가 된 것을 확인할 수 있다.

다시 한번 디렉토리 파일을 확인해보면 hello.world.war 파일이 추가된 것을 확인할 수 있다.

cat Dockerfile 명령어로 도커파일에는 어떤 내용이 들어가 있는지 꼭 확인해야한다.
내가 빌드하려는 war파일의 톰캣 서버 버전과 copy하려는 war 파일 이름이 정확히 기입되어 있는지 확인하고, 만약 버전과 파일 이름이 잘못 되었다면 필두로 vi 편집기로 수정을 해야한다.
나는 정확히 기입되어 있으므로 넘어가도록 하겠다.
젠킨스에서 명령어를 실행하기 전에 현재 가상 환경에 복사되어 있는 war 파일이 도커를 이용해서 실행할 수 있는 것인지 테스트를 해보자.
직접 이미지를 만들고 컨테이너를 만들어 실행해보자!

docker build -t docker-server -f Dockerfile .
docker build : Docker를 사용하여 이미지를 빌드한다.
-t docker-server : 생성할 이미지의 이름을 지정한다.
여기서 "docker-server"는 이미지의 이름이다.
-f Dockerfile : Dockerfile의 경로를 지정한다.
Dockerfile은 이미지를 빌드하기 위한 설정 파일로 여기서는 현재 디렉토리에 있는 Dockerfile을 사용한다.
"." : 빌드 컨텍스트를 지정한다.
이 명령은 현재 디렉토리를 기준으로 Dockerfile 및 다른 빌드 관련 파일들을 찾는다.

도커 이미지가 정상적으로 만들어진 것을 확인할 수 있다.

docker run -p 8081:8080 --name mytomcat docker-server:latest
호스트의 8081 포트를 컨테이너의 8080 포트와 연결하고, 실행 중인 컨테이너에 "mytomcat"이라는 이름을 지정하여 "docker-server" 이미지를 실행한다.
DooD 방식으로 도커가 연결되어 사용하고 있으므로 네트워크를 공유하기 때문에 동일한 포트를 여러 컨테이너에서 사용할 수 없다. 따라서 PC에서 사용하지 않는 8081 포트 번호를 사용하였고 이를 컨테이너에선 8080 포트로 접속하게 된다.

URL에 http://localhost:8081/hello-world/로 접속하여 실행하면 실제 톰캣 내부에 있는 서버가 잘 실행된 것을 확인할 수 있다.
지금까지 도커에서 실행했던 수동으로 작업했던 것들을 젠킨스를 통해 배포할 수 있도록 만들어보자.

docker rmi docker-server
docker stop mytomcat
docker rm mytomcat
먼저 이전에 만들었던 도커 이미지 docker-server와 도커 컨테이너 mytomcat을 지워준다. (지운 후 확인 한 상태)

rm -rf hello-world.war
그리고 war 파일도 젠킨스로부터 ssh 서버로 받아왔었는데 이 또한 지워준다.

젠킨스로 돌아와 My-Docker-Proejct의 구성을 눌러 Transfer Set을 수정한다.
이전엔 Exec command를 공란으로 저장했으나 도커에서 안에서 이미지를 만들기 위해, 컨테이너를 실행하기 위해 썼던 명령어를 여기에 써준다.
docker build --tag=cicd-project -f Dockerfile .;
docker run -d -p 8081:8080 --name mytomcat cicd-project:latest

그리고 저장한 뒤, 동일하게 지금 빌드를 눌러 빌드해준 뒤

성공하였는지 콘솔을 확인한다.

docker images
docker ps
ls -l
그리고 ssh 서버로 돌아와 war파일과 이미지, 컨테이너 프로세스를 확인해보면 자동으로 생긴 것을 확인할 수 있다.

동일하게 URL에 http://localhost:8081/hello-world/로 접속하여 실행하면 실제 톰캣 내부에 있는 서버가 잘 실행된 것을 확인할 수 있다.

여기서 문제는 또 다시 지금 빌드를 실행하게 되면

실패를 하게된다.


이번엔 현재 디렉토리에 있던 war 파일, 컨테이너, 이미지를 삭제한 후 다시 실행해보자

그러면 빌드가 성공하게 된다.
초기에 빌드 후 컨테이너가 작동 중인 상태에서, 이미지가 있는 상태에서 한 번 더 실행했더니 실패하였다. 그리고 다시 한번 빌드하고 싶다면 수작업으로 컨테이너 지우고 이미지 지우고 그런 작업들을 한 다음에 다시 한번 빌드하게 되면 또 성공을 한다.
이 부분에 대해서는 삭제하는 작업을 넣어주거나 별도로 제어할 수 있는 프로그램을 도입해주어야 한다.
여기에 대한 설명은 다음 포스트에 하겠다..🤭