전자책 출간 알림 [마이크로서비스패턴 쉽게 개발하기]

티스토리 뷰

4. 쿠버네티스 개발에서 배포까지 실습

개발 측면의 쿠버네티스 리소스인 인그레스, 서비스, 파드, 컨피그맵, 시크릿, 퍼시스턴트 볼륨, 퍼시스턴트 볼륨 클레임을 좀 더 확실하게 이해하기 위해 예제를 갖고 실습해 보겠습니다.

예제는 OTT 추천 서비스의 멤버 어플리케이션과 추천 어플리케이션입니다. 이 어플리케이션들은 스프링부트Spring Boot로 개발되어 있습니다.
뭔가 거창한 것 같지만 주소를 치면 결과를 간단하게 보여주는 어플리케이션들입니다.
멤버 마이크로서비스는 사용자ID에 대한 사용자 정보를 제공 합니다.
http://{인그레스 주소}/member/members/{user id}


추천 어플리케이션은 사용자 ID에 대한 추천 OTT 정보를 제공 합니다.
http://{인그레스 주소}/recommend/bestott/{user id}

 

4.1 쿠버네티스 오브젝트 구성

어플리케이션 개발에서 배포까지의 과정을 다시 한번 말씀 드리면 아래와 같습니다.

❶ 개발 및 소스 업로드: 개발한 어플리케이션을 깃 리포지토리에 업로드
❷ 컨테이너 이미지 빌드: 깃 리포지토리에서 소스를 다운로드 하여 컨테이너 이미지 빌드
❸ 컨테이너 이미지 업로드: 이미지 레지스트리에 컨테이너 이미지를 업로드
❹ 배포 요청: 쿠버네티스 클러스터의 컨트롤 플레인에 배포 정의 파일을 전달하면서 배포 요청
❺ 컨테이너 실행: 도커 허브에서 이미지를 내려 받아 컨테이너를 실행 합니다.



위 절차를 통해서 쿠버네티스 클러스터에 배포한 쿠버네티스 오브젝트의 구성은 아래와 같습니다.


그럼 위 절차대로 member, recommend 어플리케이션을 컨테이너화 하여 쿠버네티스 오브젝트로 배포해 보겠습니다.

4.2 사전 준비 사항

실습을 위해 아래 사항들을 먼저 준비 해야 합니다.

1) Open JDK와 메이븐 설치
자바 스프링 부트로 개발된 어플리케이션이므로 Open JDK(Java Development Kit)와 메이븐maven 설치를 먼저 해야 합니다.
메이븐은 컴파일, 테스트, 패키징하는 빌드 툴이고 최종 실행 파일인 jar를 만들어 줍니다.
Open JDK는 자바 개발을 위한 라이브러리와 실행 환경을 제공해 주는 오픈 소스입니다.

아래 글을 참조 하여 Open JDK와 메이븐을 PC와 배천노드에 모두 설치하여 주십시오.
Open JDK는 Java 11버전, 메이븐은 3.8.4 버전으로 설치하여 주십시오.
https://happycloud-lee.tistory.com/186

<팁>
PC에 이미 다른 버전의 Open JDK와 메이븐이 설치되어 있고 Java 11 이상이면 그대로 쓰셔도 됩니다.
</>

2) MS Visual Studio Code에 확장팩 설치
스프링부트 기반 개발을 위해 vscode에 아래 2개 확장팩을 설치 하십시오.
- Java extension pack
- Spring Boot Extension Pack



4.3 개발 및 소스 업로드


1) 깃 리포지토리 포크Fork
본인의 GitHub 레지스트리를 로그인 하십시오.
그리고 아래 GitHub 리포지토리를 접근하고 본인의 GitHub로 포크fork 하십시오.
https://github.com/hiondalott/member
https://github.com/hiondalott/recommend





본인 GitHub 리포지토리에 member와 recommend가 아래와 같이 생성되어야 합니다.


2) 리포지토리 클론
PC에서 ‘{사용자 홈 디렉토리}/k8s/ott’디렉토리를 만들고 콘솔창에서 그 디렉토리로 이동 합니다.
예를 들면 맥에서는 아래와 같이 하시면 됩니다.

mkdir -p ~/k8s/ott && cd ~/k8s/ott


본인 깃허브 리포지토리를 클론 합니다.
각 리포지토리 주소는 아래와 같이 리포지토리를 들어가 [Code]를 클릭하면 확인할 수 있습니다.


소스를 아래 예제와 같이 다운로드 합니다.
<주의>
깃 리포지토리 주소는 본인것이 맞는지 잘 확인 하고 수행 하십시오.
</>

~/k8s/ott
❯ git clone https://github.com/hiondal/member.git
'member'에 복제합니다...

~/k8s/ott
❯ git clone https://github.com/hiondal/recommend.git
'recommend'에 복제합니다...




3) 소스 이해
‘code .’을 입력하여 vscode를 실행 합니다.

~/k8s/ott
❯ code .

member 어플리케이션의 src > main > java/com/ott/member > Controller.java를 보시면 ❶ ‘/members/{id}’로 요청 받으면 ❷ members.getMember(id)를 호출하여 그 결과를 리턴하는 것을 알 수 있습니다.


Class ‘Members’보시면 ‘getMember’ 메소드는 ‘memberData’라는 맵 객체에서 요청받은 id의 데이터를 리턴 합니다.


클래스 ‘Members’의 memberData의 값을 채우는 클래스는 ‘MembersConfig.java’입니다.
‘MembersConfig’클래스는 ❶ 스프링 빈Bean으로 정의되어 있어 위 ‘Controller’클래스에서 @Autowired로 불러서 사용할 수 있습니다. ❷ ‘ottmember.filepath’라는 설정값에서 데이터가 있는 파일 경로를 얻고 ❸ ‘ottmember.authtoken’이라는 설정값에서 인증토큰을 얻습니다. ❹ 설정값에서 구한 인증 토큰 값이 맞는지 검사를 하고 ❺ 최종 데이터 파일의 경로를 구한 후 ❻ 그 파일을 열어 memberData 값을 채우게 됩니다.


설정 ‘ottmember.filepath’과 ‘ottmember.authtoken’은 src > main > resources의 application.yaml의 ❶ 번과 같이 정의 되어 있습니다.
ottmember.filepath는 OS 환경변수 ‘ottmember_filepath’에서 값을 읽고 ottmember.authtoken은 OS 환경변수 ‘ottmember_authtoken’에서 값을 읽습니다.
또한 ❷ 어플리케이션이 사용하는 포트도 OS 환경 변수 ‘service_port’의 값을 읽고 기본 값은 ‘3001’이라는 걸 알 수 있습니다.



pom.xml을 보면 ❶ ‘finalName’으로 ‘member’라고 지정되어 있습니다. 실행 파일을 ‘member.jar’로 만들기 위한 설정입니다. 이 설정이 빠져 있으면 pom.xml의 ‘artifactId’와 ‘version’값을 참조하여 ‘member-0.0.1-SNAPSHOT.jar’로 만들어 집니다.


어플리케이션 ‘recommend’도 어플리케이션 ‘member’와 유사한 구조로 개발되어 있습니다.
위 설명을 참조하여 ‘recommend’어플리케이션도 파악해 보시기 바랍니다.
두 어플리케이션을 정리하면 아래와 같습니다.

서버 포트
OS환경변수
인증토큰
OS환경변수
데이터 파일 경로
OS 환경변수
API 경로
member service_port
기본값: 3001
ottmember_authtoken
기본값: P@ssword!
ottmember_filepath
기본값: data/members.properties
/members
/{id}
recomm
end
service_port
기본값: 3002
ottrecommend_authtoken
기본값: P@ssword!
ottrecommend_filepath
기본값: data/bestott.properties
/bestott/{id}


4) 어플리케이션 실행
어플리케이션이 정상 동작하려면 {사용자 홈 디렉토리}/data/members.properties파일과 {사용자 홈 디렉토리}/data/bestott.properties파일이 있어야 합니다.
아래 예제를 참고하여 만드시기 바랍니다. 소스를 보시면 아시겠지만 ‘{id}={value}’형식으로 만드시면 되고 {value}부분은 어떤 값이든 상관 없습니다.

TIP) {사용자 홈 디렉토리} 가기 

# Mac/Linux
$ cd ~

# Windows
cd %userprofile%

홈 디렉토리 밑에 /data 디렉토리를 만들고 아래 2파일을 만드세요.

{사용자 홈 디렉토리}/data/members.properties
ondal=온달,남자,hiondal@gmail.com
user1=유저1,여자,user1@gmail.com
user2=유저2,여자,user2@gmail.com

{사용자 홈 디렉토리}/data/bestott.properties
ondal=Netflix,https://www.netflix.com
user1=Disney+,https://www.disneyplus.comm
user2=WATCHA,https://watcha.com


파일을 만드셨으면 실행을 해 보십시오.
‘SPRING BOOT DASHBOARD’에서 ❶ 두 어플리케이션을 한꺼번에 실행하거나, ❷ 하나씩 실행할 수 있습니다.


최초로 실행할때는 라이브러리를 다운로드 하는데 시간이 좀 걸립니다.
‘디버그 콘솔’ 탭을 누르면 어플리케이션 로그를 볼 수 있습니다. 아래와 같이 지정된 포트로 시작하면 잘 실행된 겁니다.


메이븐의 실행 파일 패키징 방법
메이븐은 아래와 같은 순서로 실행 파일을 패키징 합니다.
1) pom.xml의 ‘dependencies’항목에 정의된 라이브러리 정보 읽음
2) 로컬 메이븐 리포지토리에서 그 라이브러리를 찾음. 기본 로컬 메이븐 리포지토리는 ‘{사용자 홈 디렉토리}/.m2’
3) 로컬 메이븐 리포지토리에서 못 찾으면 원격 메이븐 리포지토리(https://mvnrepository.com)에서 라이브러리를 로컬 메이븐 리포지토리로 다운로드 함
4) 어플리케이션을 컴파일 함
5) 어플리케이션의 테스트 코드를 실행하여 테스트
6) 어플리케이션 소스와 로컬 메이븐 리포지토리의 라이브러리들을 패키징하여 실행파일을 만듬



이제 웹브라우저를 열고 API주소를 호출하여 잘 동작하는지 확인 하십시오. 맨 마지막 ‘{id}’값은 데이터 파일에서 정의한 id값과 같아야 합니다.

http://localhost:3001/members/{id}

http://localhost:3002/bestott/{id}

5) 소스 업로드
잘 실행 되셨나요 ?
그럼 소스를 다시 깃 허브 리포지토리로 업로드 합니다.
수정된 소스가 있어야 하므로 각 어플리케이션의 README.md파일에 아무 값이나 추가하고 업로드 합니다.
‘Git’ 명령을 터미널에서 해도 되지만 아래와 같이 vscode의 기능을 이용하셔도 됩니다.
❶ 작업바에서 3번째 아이콘을 누르고 ❷ 커밋 메시지를 입력한 후 ❸ 체크 아이콘을 누르십시오.
‘Git’명령의 ‘git add .’와 ‘git commit -m {메시지}’와 동일한 수행입니다.


[동기화 변경 내용] 버튼을 눌러 업로드 합니다.
‘Git’명령의 ‘git push -u origin main’과 동일한 수행입니다.



4.4 컨테이너 이미지 빌드 및 업로드


이제 ❷ 번 과정인 배천 노드에 소스 다운로드와 컨테이너 이미지 빌드를 수행 합니다.
그리고 ❸번 이미지 레지스트리에 컨테이너 이미지 업로드까지 합니다.


1) 소스 다운로드
배천 노드를 로그인 합니다.
배천 노드에 작업 디렉토리를 만들고 이동 합니다. 작업 디렉토리는 PC와 동일하게 ‘~/k8s/ott’로 하겠습니다.

[root@osboxes ~]# mkdir -p ~/k8s/ott && cd ~/k8s/ott


자신의 깃허브 레지스트리에서 member 리포지토리와 recommend 리포지토리를 클론 합니다.

[root@osboxes ott]# git clone https://github.com/hiondal/member.git
Cloning into 'member'...

Resolving deltas: 100% (32/32), done.
[root@osboxes ott]# git clone https://github.com/hiondal/recommend.git
Cloning into 'recommend'...

Unpacking objects: 100% (71/71), 56.98 KiB | 1.32 MiB/s, done.
[root@osboxes ott]# ll
total 0
drwxr-xr-x. 6 root root 130 Jan  8 02:51 member
drwxr-xr-x. 5 root root 102 Jan  8 02:51 recommend


2) 실행파일 만들기
메이븐을 이용하여 실행파일을 만듭니다. 최초 실행할 때는 라이브러리들을 로컬 메이븐 리포지토리에 다운로드 받아야 하므로 시간이 조금 걸립니다.

어플리케이션 ‘member’의 실행파일을 만듭니다. 수행이 완료되면 target 디렉토리에 ‘member.jar’파일이 생성 됩니다.

[root@osboxes ott]# cd member
[root@osboxes member]# mvn clean package -DskipTests
...
[root@osboxes member]# ll target
...
-rw-r--r--. 1 root root 17558437 Jan  8 03:19 member.jar
...




어플리케이션 ‘recommend’의 실행파일을 만듭니다. 수행이 완료되면 target 디렉토리에 ‘recommend.jar’파일이 생성 됩니다.

[root@osboxes ott]# cd recommend
[root@osboxes recommend]# mvn clean package -DskipTests
...
[root@osboxes recommend]# ll target
...
-rw-r--r--. 1 root root 17558218 Jan  8 03:19 recommend.jar
...



3) 컨테이너 이미지 빌드
컨테이너 이미지 정의 파일인 도커파일Dockerfile을 만듭니다.
도커파일은 제가 미리 올려 놓은 파일을 아래와 같이 각 어플리케이션 디렉토리에 다운로드 하십시오.

[root@osboxes ott]# cd member
[root@osboxes member]# wget -O Dockerfile https://hiondal.github.io/k8s-yaml/dockerfiles/Dockerfile4java


[root@osboxes member]# cd ../recommend

[root@osboxes member]# wget -O Dockerfile https://hiondal.github.io/k8s-yaml/dockerfiles/Dockerfile4java




Dockerfile의 내용을 봅니다.

[root@osboxes member]# vim Dockerfile

 


❶ 베이스 이미지 정의
❷ 이미지 빌드할 때 실행파일 이름을 ARTIFACTORY_FILE라는 파라미터로 받음
❸ ‘docker’유저 생성, sudo 권한 부여, 홈 디렉토리 생성, 홈 디렉토리에 권한 부여
❹ 작업 디렉토리를 홈 디렉토리로 지정
❺ target디렉토리에 생성된 실행파일을 컨테이너 이미지 안의 홈 디렉토리로 복사
❻ 실행파일 실행

Dockerfile을 닫고 나갑니다. ESC > ‘:q’ 입력하고 엔터 치면 됩니다.

아래 명령으로 각 어플리케이션의 컨테이너 이미지를 만듭니다.
<주의>
이미지 오거니제이션(아래 예에서는 ‘hiondal’)은 반드시 본인의 도커 허브 유저명으로 바꾸셔야 합니다.
</>
파라미터 ARTIFACTORY_FILE을 ‘member.jar’로 넘겼기 때문에 이 파일은 이미지안의 홈 디렉토리인 ‘/home/docker’로 복사 됩니다.

[root@osboxes ott]# cd member
[root@osboxes member]# docker build --build-arg ARTIFACTORY_FILE=member.jar -t hiondal/member:0.0.1 .

[root@osboxes member]# cd ../recommend
[root@osboxes recommend]# docker build --build-arg ARTIFACTORY_FILE=recommend.jar -t hiondal/recommend:0.0.1 .



4) 이미지 레지스트리로 업로드
만들어진 이미지를 이미지 레지스트리로 업로드 합니다.
이미지 레지스트리는 도커 허브를 계속 이용 합니다.

도커 허브에 로그인 합니다.

[root@osboxes recommend]# cd
[root@osboxes ~]# docker login docker.io


컨테이너 이미지를 이미지 레지스트리로 푸시 합니다.
<주의>
이미지 오거니제이션(아래 예에서는 ‘hiondal’)은 반드시 본인의 도커 허브 유저명으로 바꾸셔야 합니다.
</>

[root@osboxes ~]# docker push hiondal/member:0.0.1
The push refers to repository [docker.io/hiondal/member
...
[root@osboxes ~]# docker push hiondal/recommend:0.0.1
The push refers to repository [docker.io/hiondal/recommend
...




4.5 쿠버네티스 클러스터에 컨테이너 실행


이제부터 과정이 본 실습 과정의 핵심 입니다.
❹ 번 과정에서 파드 실행을 위해 디플로이먼트 오브젝트를 만듭니다. 파드 내에 환경변수를 생성하기 위해 컨피그맵과 시크릿 오브젝트도 만듭니다. 또한 데이터 파일을 파드 내에 마운트 하기 위한 퍼시스턴트 볼륨과 퍼시스턴트 볼륨 클레임 오브젝트도 만들어야 합니다. 디플로이먼트 오브젝트가 생성되면서 ❺ 도커 허브에서 컨테이너 이미지를 내려 받아 파드가 실행되게 됩니다.
파드 실행 후에는 파드 로드 밸런서인 서비스 오브젝트와 서비스 로드밸런서인 인그레스 오브젝트를 생성 합니다.


그럼 아래 OTT 추천 서비스의 쿠버네티스 오브젝트 생성 순서에 따라 각 오브젝트를 만들어 보겠습니다.


쿠버네티스 오브젝트 실습은 빠르게 하고 대시보드 사용법도 익히기 위해 쿠버네티스 대시보드를 이용 합니다.
쿠버네티스 대시보드는 위 설치 가이드대로 했다면 http://mydashboard.io일겁니다.
대시보드를 인증 토큰을 사용하여 로그인 하십시오.
인증 토큰은 아래와 같이 구하실 수 있습니다.

[root@osboxes yaml]# k get secret -n kube-system | grep admin
kube-admin-token-h89bz     kubernetes.io/service-account-token …
[root@osboxes yaml]# k describe secret kube-admin-token-h89bz -n kube-system

Data
====

token:      eyJhbGciOiJS…pEPO8b7Iw


웹브라우저의 새 탭을 여시고 https://github.com/hiondal/k8s-yaml/tree/main/3.4 페이지를 열어 주십시오.
이 깃 허브 페이지에는 오브젝트 생성을 위한 야믈 파일들이 있습니다.

시작 하기 전에 작업할 네임스페이스 부터 만들겠습니다.

깃 허브 페이지의 ns.yaml파일을 열고 ‘복사'버튼을 이용하여 내용을 클립보드에 복사합니다.



대시보드에서 ❶ 현재네임스페이스를 ‘default’로 변경하고 ❷ 신규 리소스 생성 버튼을 클릭한 후 ❸ 클립보드에 복사한 내용을 붙여넣기 하고 생성할 네임스페이스명을 ott로 합니다.
그리고 하단의 [업로드] 버튼을 눌러 오브젝트를 생성 하십시오.




네임스페이스를 생성한 ‘ott’로 변경하고 왼쪽 메뉴를 내려 ‘서비스 어카운트'를 클릭 합니다.
네임스페이스가 만들어지면 ‘default’라는 이름으로 서비스 어카운트가 자동으로 만들집니다.

쿠버네티스의 어느 컴포넌트가 기본 서비스 어카운트를 만드는 걸까요 ?
바로 답이 나오신다면 쿠버네티스 아키텍처를 잘 이해하신거고 아니라면 쿠버네티스 아키텍처를 잠깐 보시고 답을 찾아 보십시오.
답은 컨트롤 플레인의 ‘컨트롤러 매니저’입니다.


또한 ‘default’ 서비스 어카운트에 대한 인증 토큰을 담고 있는 시크릿도 자동으로 만들어 집니다.
k8s 1.25부터는 보안 강화를 위해 Secret이 자동으로 만들어지지 않습니다. 


파드를 실행할 때 기본 서비스 어카운트인 ‘default’를 사용해도 되지만 보통은 새로운 서비스 어카운트를 만들어서 사용합니다.
야믈파일 ‘serviceaccount.yaml’의 내용을 대시보드에 붙여넣어 서비스 어카운트 ‘sa-ott’를 생성 하십시오.

k8s 1.25이상에서는 Secret을 수동으로 만들어 줘야 합니다.  

 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-ott
  namespace: ott
---
apiVersion: v1
kind: Secret
metadata:
  name: sa-ott-secret
  namespace: ott
  annotations:
    kubernetes.io/service-account.name: sa-ott
type: kubernetes.io/service-account-token


‘sa-ott’가 생성되면 자동으로 시크릿이 만들어지는 것도 대시보드에서 확인해 보십시오.

조금만 더 작업하셔야 합니다.
방금 만든 서비스 어카운트에 권한을 부여해야 합니다. ‘sa-ott’는 네임스페이스 ‘ott’에는 모든 권한을 부여하고 다른 네임 스페이스는 읽기 권한만 부여 합니다.
먼저 야믈파일 ‘rolebinding.yaml’을 이용하여 롤바인딩 ‘rb_sa-ott’를 만듭니다.
야믈 내용을 보면 ClusterRole인 ‘admin’권한을 네임스페이스 ‘ott’의 서비스 어카운트 ‘sa-ott’에 부여하는 것을 알 수 있습니다.

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rb_sa-ott
  namespace: ott
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: admin
subjects:
- kind: ServiceAccount
  name: sa-ott
  namespace: ott


다음으로 ‘sa-ott’에게 다른 네임스페이스에 대해선 조회 권한만 부여 합니다.
야믈파일 ‘clusterolebinding.yaml’파일을 이용하여 클러스터 롤 바인딩 ‘crb_ott_sa-ott’를 만듭니다.
야믈 내용을 보면 ClusterRole인 ‘view’권한을 네임스페이스 ‘ott’의 서비스 어카운트 ‘sa-ott’에 부여하는 것을 알 수 있습니다.

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: crb_ott_sa-ott
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
- kind: ServiceAccount
  name: sa-ott
  namespace: ott


대시보드에서 롤 바인딩 오브젝트 ‘rb_sa-ott’와 클러스터 롤 바인딩 오브젝트 ‘crb_ott_sa-ott’의 정보를 보면 ‘rb_sa-ott’는 네임스페이스 정보가 있지만 ‘crb_ott_sa-ott’는 네임스페이스 정보가 없는 것을 확인할 수 있습니다.
즉 ‘rb_sa-ott’는 네임스페이스 ‘ott’에만 적용되는 권한 바인딩이고 ‘crb_ott_sa-ott’는 전체 네임스페이스에 적용되는 권한 바인딩이라는 의미 입니다.

 

네임스페이스 ‘ott’, 서비스 어카운트 ‘sa-ott’, 롤바인딩 ‘rb_sa-ott’, 클러스터 롤 바인딩 ‘crb_ott_sa-ott’를 만들었습니다.
이제 네임스페이스 ‘ott’에 필요한 오브젝트들을 만들어 봅시다.


1) 환경변수 생성을 위한 컨피그맵과 시크릿 오브젝트 생성
애플리케이션별로 필요한 환경 변수는 아래와 같이 서버 포트, 인증토큰, 데이터 파일 경로입니다.
인증 토큰은 중요한 정보이므로 시크릿으로 만들고 나머지는 컨피그맵으로 만드는게 좋겠죠 ?

서버 포트
OS환경변수
인증토큰
OS환경변수
데이터 파일 경로
OS 환경변수
member service_port
기본값: 3001
ottmember_authtoken
기본값: P@ssword!
ottmember_filepath
기본값: data/members.properties
recommend service_port
기본값: 3002
ottrecommend_authtoken
기본값: P@ssword!
ottrecommend_filepath
기본값: data/bestott.properties


데이터 파일 경로 OS 환경 변수 생성을 위한 컨피그맵을 만듭니다. 서버 포트 환경변수는 디플로이먼트 오브젝트에서도 정의할 수 있어서 연습을 위해 컨피그맵으로는 안 만들겠습니다.

야믈 파일 ‘cm-member.yaml’의 내용 복사하여 컨피그맵 ‘member-cm’을 만듭니다.
대시보드 좌측 메뉴의 ‘컨피그 및 스토리지 > 컨피그 맵'을 눌러 생성된 컨피그 맵 내용을 확인해 보십시오.

kind: ConfigMap
apiVersion: v1
metadata:
  name: member-cm
  namespace: ott
data:
  ottmember_filepath: data/members.properties


야믈 파일 ‘cm-recommend.yaml’의 내용 복사하여 컨피그맵 ‘recommend-cm’을 만듭니다.
대시보드 좌측 메뉴의 ‘컨피그 및 스토리지 > 컨피그 맵'을 눌러 생성된 컨피그 맵 내용을 확인해 보십시오.

kind: ConfigMap
apiVersion: v1
metadata:
  name: recommend-cm
  namespace: ott
data:
  ottrecommend_filepath: data/bestott.properties




야믈 파일 ‘secret-member.yaml’의 내용 복사하여 시크릿 ‘member-secret’을 만듭니다.
시크릿 데이터의 값은 BASE64로 인코딩되어 있습니다.
대시보드 좌측 메뉴의 ‘컨피그 및 스토리지 > 시크릿'을 눌러 생성된 시크릿 내용을 확인해 보십시오.

kind: Secret
apiVersion: v1
metadata:
  name: member-secret
  namespace: ott
type: Opaque
data:
  ottmember_authtoken: UEBzc3dvcmQh


리눅스 명령어로 문자열을 BASE64로 인코딩/디코딩을 할 수 있습니다.
- 인코딩: echo {문자열} | base64
- 디코딩: echo {인코딩된 문자열} | base64 -d

인코딩 예) echo P@ssword! | base64 ⇒ UEBzc3dvcmQh
디코딩 예) echo UEBzc3dvcmQh | base64 -d ⇒ P@ssword!

아래와 같이 원래 데이터의 값을 쉽게 확인할 수 있고 그 옆의 ‘편집' 아이콘 버튼으로 값도 바꿀 수 있습니다.


야믈 파일 ‘secret-recommend.yaml’의 내용 복사하여 시크릿 ‘recommend-secret’을 만듭니다.
대시보드 좌측 메뉴의 ‘컨피그 및 스토리지 > 시크릿'을 눌러 생성된 시크릿 내용을 확인해 보십시오.

kind: Secret
apiVersion: v1
metadata:
  name: recommend-secret
  namespace: ott
type: Opaque
data:
  ottrecommend_authtoken: UEBzc3dvcmQh




2) 스토리지 사용을 위한 퍼시스턴트 볼륨과 퍼시스턴트 볼륨 클레임 오브젝트 생성
아래 그림과 같이 퍼시스턴트 볼륨 ‘ott’는 물리적인 디렉토리인 ‘/data/ott’를 사용하기 위한 오브젝트입니다. ‘/data/ott’는 파드가 실행되는 워커노드에 만들면 됩니다.
퍼시스턴트 볼륨 클레임 ‘ott’는 퍼시스턴트 볼륨 ‘ott’와 바인딩 되고 파드가 실행될 때 파드안의 ‘/home/docker/data’디렉토리로 마운트 됩니다.
결론적으로 파드 안에서 동작하는 애플리케이션이 ‘/home/docker/data’디렉토리를 접근하면 실제로는 워커 노드의 ‘/data/ott’디렉토리를 접근하게 되는 것입니다.



왜 파드안에서 ‘/home/docker/data’디렉토리로 마운트 해야 할까요 ?
그 이유를 이미 아시리라 생각하지만 혹시나 해서 명확히 설명 하겠습니다.

파드를 실행하는 유저가 ‘docker’이고 그 홈디렉토리는 ‘/home/docker’입니다.

FROM openjdk:11-jre-slim


ENV USERNAME docker
ENV ARTIFACTORY_HOME /home/${USERNAME}


WORKDIR ${ARTIFACTORY_HOME}

# Launch the artifactory as docker user
ENTRYPOINT [ "sh", "-c" ]
USER docker
CMD [ "java -jar ${ARTIFACTORY_FILE} --spring.profiles.active=${PROFILE}" ]

그리고 데이터를 읽는 파일이 아래와 같이 {홈디렉토리}/data밑에 있기 때문입니다. 

이 파일 경로는 위에서 ConfigMap내에 정의했습니다.  

데이터 파일 경로
OS 환경변수
ottmember_filepath
기본값: data/members.properties
ottrecommend_filepath
기본값: data/bestott.properties

예제 애플리케이션은 ‘{사용자 홈 디렉토리}/data’디렉토리에서 데이터 파일을 읽도록 프로그램 되어 있습니다.

@Configuration
public class MembersConfig {

   @Value("${ottmember.filepath}")
  private String ottMemberFilepath;

  …
  @Bean
  public Members loadMembers() {

      …


      String filepath = System.getProperty("user.home") + File.separator + ottMemberFilepath;
      …
   
  }
}


따라서 ‘/home/docker/data’디렉토리로 워커 노드의 ‘/data/ott’디렉토리가 마운트 되어야 데이터 파일을 읽을 수 있기 때문입니다.

PV와 PVC를 만들기 전에 워커노드에 ‘/data/ott’디렉토리를 만들고 데이터 파일인 ‘members.properties’와 ‘bestott.properties’파일을 만들어야 겠죠 ?
배천 노드에서 아래와 같이 워커 노드를 로그인 합니다.

<팁>
워커 노드를 암호 없이 어떻게 로그인하는지 궁금하신 분들은 아래 설치 가이드 페이지를 다시 보시면 됩니다.
https://happycloud-lee.tistory.com/35#03
</>

[root@osboxes ~]# ssh w1
Last login: Sat Jan  8 08:42:19 2022 from 223.62.204.173
[root@worker1 ~]# mkdir -p /data/ott && cd /data/ott


PC에서 만든 데이터 파일들의 내용을 복사하여 이 디렉토리에 파일들을 만듭니다. 그리고 ‘exit’를 실행하여 배천 노드로 돌아갑니다.

[root@worker1 ott]# vim members.properties
[root@worker1 ott]# vim bestott.properties

[root@worker1 ott]# exit
[root@osboxes ~]# 


야믈 파일 ‘volume-ott.yaml’의 내용을 복사하여 PV와 PVC를 만듭니다.
<팁>
‘volume-ott.yaml’을 보면 퍼시스턴트 볼륨 오브젝트와 퍼시스턴트 볼륨 클레임 오브젝트 정의 사이에 ‘---’로 구분되어 있습니다. 이렇게 ‘---’으로 구분하여 하나의 파일에 여러개의 오브젝트를 정의할 수 있습니다.
</>

야믈 파일 내용 중 PV정의 내용을 보면 ❶ ‘standard’라는 스토리지 클래스를 이용하고, ❷ 호스트의 ‘/data/ott’디렉토리를 사용하겠다는 정의를 볼 수 있습니다.
스토리지 클래스는 스토리지의 유형을 정의하는 리소스입니다. 스토리지 제품 종류에 따라 모두 다르기 때문에 스토리지 벤더의 문서를 참조하여 정의해야 합니다.
스토리지 클래스 ‘standard’는 파일 스토리지 유형 중 가장 기본이 되는 오브젝트입니다.
‘standard’라는 스토리지 클래스 오브젝트는 아직 안 만들었지만 PV는 일단 잘 만들어질겁니다. 이 오브젝트는 조금 이따 만들겠습니다.


PVC 정의 부분을 보면 ❶ ‘selector’항목에 어떤 PV와 바인딩할 지 정의하고 있습니다.
아래와 같이 레이블 ‘service’의 값이 ‘ott’인 PV와 바인딩 해 달라고 정의되어 있습니다.
위 PV의 ‘metadata.labels’를 보면 레이블 ‘service’의 값이 ‘ott’이기 때문에 이 PVC ‘ott’ 오브젝트는 PV ‘ott’와 바인딩 되는 것입니다.


<팁>
PVC의 ‘selector’가 없으면 storageClassName, resources.requests.storage, accessModes에 지정한 조건에 맞는 PV와 바인딩 됩니다.
</>

대시보드의 ‘클러스터 > 퍼시스턴트 볼륨' 메뉴를 눌러 PV ‘ott’가 생성된 것을 확인해 보십시오.
또한 ‘컨피그 및 스토리지 > 퍼시스턴트 볼륨 클레임' 메뉴를 눌러 PVC ‘ott’가 생성된 것도 확인해 보십시오.
보시면 아시겠지만 PVC는 네임스페이스 ‘ott’에 생성되는 것이고 PV는 클러스터 레벨에서 생성되는 오브젝트입니다.

이제 스토리지 클래스 ‘standard’를 만들겠습니다.
야믈 파일 ‘storageclass.yaml’을 이용하여 생성 하십시오. 스토리지 유형에 따라 정의가 달라지므로 자세한 설명은 생략 하겠습니다. ‘11. 데이터 저장소 사용을 위한 PV/PVC’에서 조금 더 다루도록 하겠습니다.
생성된 스토리지 클래스 오브젝트는 ‘컨피그 및 스토리지 > 스토리지 클래스'에서 확인할 수 있습니다.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: standard
provisioner: kubernetes.io/no-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate



3) 파드 실행과 컨트롤을 위한 디플로이먼트 오브젝트 생성
이제 파드 실행을 위한 준비를 마쳤습니다. 드디어 파드를 실행할 순서입니다.

야믈 파일 ‘deploy-member.yaml’을 이용하여 파드 ‘member’ 오브젝트를 생성 하십시오.
<주의>
❻ 번 이미지 경로에서 두번째 파트인 오거니제이션(아래 예에서는 ‘hiondal’)은 본인의 도커 허브 사용자명으로 바꾸셔야 합니다.
</>


❶ 파드를 실행하고 컨트롤할 워크로드 컨트롤러의 종류를 지정 합니다.
❷ 컨트롤 대상 파드를 정의합니다. ❹ ‘template’ 하위 부터 파드에 대한 정의인데 거기에 레이블 ‘app’의 값이 ‘member’인 파드를 컨트롤 하겠다는 의미입니다.
❸ 몇개의 파드를 생성할 지 정의 합니다.
❹ ‘template’하위의 정의가 파드에 대한 정의 입니다. 이 하위 설정 값대로 파드가 실행 됩니다.
❺ 파드를 실행할 서비스 어카운트를 정의 합니다. 이 서비스 어카운트가 적절한 권한이 있어야 파드가 실행 됩니다. 앞에서 서비스 어카운트 ‘sa-ott’에게 네임스페이스 ‘ott’에 대한 전체 권한을 주었기 때문에 문제 없이 파드가 실행 됩니다.
❻ 이미지의 경로를 지정합니다. 이미지 레지스트리의 값이 ‘docker.io’이기 때문에 도커 허브에서 내려 받습니다. 이미지 경로의 두번째 파트인 오거니제이션은 본인 오거니제이션인 도커 허브의 사용자명으로 바꾸셔야 합니다.
❼ 디플로이먼트 오브젝트 야믈에서 직접 환경변수를 정의할 수 있습니다. 어플리케이션 실행 포트를 지정 합니다.
❽ 환경 변수를 컨피그맵을 참조하여 생성하는 방법입니다.
❾ 환경 변수를 시크릿을 참조하여 생성하는 방법입니다.
❿ 파드내에 어떤 디렉토리로 마운트 할지를 지정 합니다. ‘사용자 홈 디렉토리'인 ‘/home/docker’ 하위의 ‘data’로 마운트 하도록 설정 합니다.
⓫ 볼륨을 마운트 하기 위해 참조할 퍼시스턴트 볼륨 클레임을 정의합니다.

대시보드의 ‘워크로드 > 파드'메뉴를 클릭하여 파드가 정상적으로 실행 되었는지 확인 합니다.
파드 정보를 찬찬히 보시면 위 디플로이먼트 야믈에서 정의한 내용과 실행 결과 내용을 볼 수 있습니다.
‘워크로드 > 디플로이먼트'를 클릭하여 워크로드 컨트롤러 오브젝트 ‘member’의 정보도 확인해 보십시오.

‘recommend’ 파드도 실행 합니다.
야믈 파일 ‘deploy-recommend.yaml’을 이용하여 디플로이먼트 오브젝트 ‘recommend’와 파드 오브젝트를 생성 하십시오.

<팁>
디플로이먼트 오브젝트를 생성하면 파드 외에 ‘레플리카 셋'이라는 오브젝트도 생성 됩니다.
이 레플리카 셋이 직접적으로 파드를 실행하고 컨트롤하는 워크로드 컨트롤러 리소스입니다.
디플로이먼트 리소스는 레플리카 셋 리소스를 추상화한 상위 리소스입니다.
</>

대시보드에서 파드를 선택하여 들어가서 ❶ 파드의 로그 확인과 ❷ 파드 안으로 진입하는 기능을 쉽게 이용할 수 있습니다.




4) 파드 로드 밸런싱을 위한 서비스 오브젝트 생성
파드 로드 밸런서 서비스 오브젝트를 생성 합니다.

야믈 파일 ‘svc-member.yaml’내용을 이용하여 서비스 오브젝트 ‘member’를 생성 합니다.

apiVersion: v1
kind: Service
metadata:
  name: member
  namespace: ott
spec:
  type: ClusterIP
  selector:
    app: member
  ports:
  - name: port1
    port: 3001
    targetPort: 3001


❶ 서비스 오브젝트의 종류를 ‘ClusterIP’로 지정합니다. 이 유형은 클러스터 외부에 서비스 오브젝트를 노출하지 않는 유형입니다.
❷ 로드 밸런싱할 파드를 찾기 위한 셀렉터입니다. 위 디플로이먼트 오브젝트 정의 시 ‘template.metadata.lables’에 보시면 레이블 ‘app’의 값이 ‘member’로 정의되어 있기 때문에 이 서비스 오브젝트는 파드 ‘member’와 연결되게 됩니다.
❸ 서비스 오브젝트의 포트를 정의 합니다. ‘ports.port’가 서비스가 수신하는 포트이고 ‘ports.targetPort’가 연결 대상이 되는 파드의 포트입니다.

서비스 오브젝트의 타켓 포트 찾기
서비스 오브젝트의 수신 포트는 아무거나 지정해도 되지만 타겟 포트는 어플리케이션에서 수신하는 포트를 정확히 지정해야 합니다.
어플리케이션의 수신 포트는 application.yaml의 ‘server.port’의 값이고 예제에서는 ‘${service_port:3001}’과 같이 환경변수 ‘service_port’의 값을 참조합니다. 따라서 아래 환경변수 ‘service_port’의 값을 서비스 오브젝트의 타겟 포트로 지정해야 합니다.
그 아래에 있는 ports.containerPort는 컨테이너 간 통신에 사용하는 포트이고 서비스 타켓 포트와는 전혀 상관 없습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: member
  namespace: ott
  labels:
    app: member
spec:
  selector:
    matchLabels:
      app: member
  replicas: 1
  template:
    metadata:
      name: member
      labels:
        app: member
    spec:
      serviceAccount: sa-ott
      containers:
      - name: member
        image: docker.io/hiondal/member:0.0.1
        imagePullPolicy: Always
        env:
        - name: service_port
          value: "3001"
        - name: PROFILE
          value: dev
        envFrom:
        - configMapRef:
            name: "member-cm"
        - secretRef:
            name: "member-secret"
        ports:
        - name: containerport
          containerPort: 3001
        ...


생성된 서비스 오브젝트는 ‘서비스 > 서비스' 메뉴에서 확인할 수 있습니다.
아래와 같이 서비스 오브젝트가 어떤 파드를 로드 밸런싱하는 지 쉽게 볼 수 있습니다.


야믈 파일 ‘svc-recommend.yaml’ 내용을 이용하여 서비스 오브젝트 ‘recommend’도 생성 합니다.



5) 서비스 로드 밸런싱을 위한 인그레스 오브젝트 생성
드디어 마지막 오브젝트인 서비스 로드 밸런서 인그레스를 생성 합니다.
야믈 파일 ‘ing-ott.yaml’ 내용을 이용하여 인그레스 오브젝트 ‘ott’를 만듭니다.

<주의>
❹ 인그레스 호스트의 IP는 반드시 본인 클러스터의 컨트롤 플레인 또는 워커 노드의 퍼블릭 IP로 바꿔야 합니다.
</>

❶ 인그레스 오브젝트에서 사용하는 인그레스 클래스 오브젝트 이름을 지정 합니다. 인그레스 컨트롤러 설치(https://happycloud-lee.tistory.com/35#12)시 자동으로 생성 됩니다. 인그레스 클래스 오브젝트를 확인하려면 배천 노드에서 ‘k get ingressclass’명령을 수행하면 됩니다. 인그레스 클래스 오브젝트명이 없으면 인그레스 오브젝트가 제대로 동작하지 않습니다.
❷ 이 어노테이션이 없으면 HTTPS프로토콜로 자동 전환 됩니다.
❸ 리라이트 룰ReWrite Rule을 정의 합니다. ❺번과 ❼번에 정의한 접근 URI경로를 어떻게 바꿔서 서비스 오브젝트에 전달할 지를 정의하는 것입니다. 예를 들어 ‘/member/members/ondal’로 접근하면 서비스 오브젝트 ‘member’로는 ‘/members/ondal’로 주소를 바꿔서 연결하게 됩니다.
❹ 인그레스 오브젝트의 호스트 이름 입니다. 중간에 IP는 본인 클러스터의 컨트롤 플레인 또는 워커노드의 퍼블릭 IP로 반드시 바꾸셔야 합니다.
❺ ‘/member/’로 시작하는 경로로 접근할 때 수행을 정의 합니다.
❻ ‘/member/’로 시작하는 경로로 접근할 때 서비스 오브젝트 ‘member’를 ‘3001’번 포트로 연결 합니다. ‘3001’번 포트는 서비스 오브젝트가 수신하는 포트입니다. 서비스 오브젝트 ‘member’의 야믈에서 ‘spec.ports.port’값과 반드시 일치해야 합니다.
❼ ‘/recommend/’로 시작하는 경로로 접근할 때 수행을 정의 합니다.
❽ ‘/recommend/’로 시작하는 경로로 접근할 때 서비스 오브젝트 ‘recommend’를 ‘3002’번 포트로 연결 합니다. ‘3002’번 포트는 서비스 오브젝트가 수신하는 포트입니다. 서비스 오브젝트 ‘recommend’의 야믈에서 ‘spec.ports.port’값과 반드시 일치해야 합니다.

<팁>
인그레스의 호스트에 지정한 ‘{sub domain}.{IP}.nip.io’는 와일드카드Wildcard DNS 형식입니다.
DNS서버가 없어서 도메인을 등록하진 못하지만 IP가 아닌 도메인으로 접근해야 하는 경우 이러한 형식으로 지정하면 해당 IP로 연결해 줍니다. ‘nip.io’ 대신에 ‘xip.io’도 사용 가능 합니다.
</>

필요한 모든 오브젝트를 생성하였습니다.
이제 정의한 인그레스 호스트와 경로로 ‘member’와 ‘recommend’ 애플리케이션이 동작하는지 테스트 하면 됩니다.
웹브라우저에서 ‘http://{인그레스 호스트}/member/members/{id}’와 ‘http://{인그레스 호스트}/recommend/bestott/{id}’로 접근해 보십시오.
아래와 같이 결과가 정상적으로 표시되면 성공입니다.

 


성공 하셨나요 ? 그렇다면 정말 축하합니다.
여러분은 이제 개발을 위한 쿠버네티스 오브젝트들을 거의 다 경험하신겁니다.
처음 하시는 분들은 좀 복잡하고 이해가 잘 안되는 부분들이 있을 수 있습니다.
그게 정상입니다.
이후의 과정을 더 진행하기 전에 실습 과정을 꼼꼼히 다시 읽어 보시면서 예제로 제공해 드린 야믈도 바꿔 가면서 완벽하게 이해하실것을 권고 드립니다.
이 실습 과정을 잘 이해하시면 이후의 과정을 따라 오시는데 큰 어려움이 없을것이기 때문입니다.

 

쿠버네티스 쉽게 이해하기 시리즈 목차

[쿠버네티스 쉽게 이해하기 1] 쿠버네티스 설치하기
[쿠버네티스 쉽게 이해하기 2] 쿠버네티스 아키텍처
[쿠버네티스 쉽게 이해하기 3] 한장으로 이해하는 쿠버네티스 리소스
[쿠버네티스 쉽게 이해하기 4] 쿠버네티스 개발에서 배포까지 실습
[쿠버네티스 쉽게 이해하기 5] 쿠버네티스 오브젝트 정의 파일 쉽게 만들기
[쿠버네티스 쉽게 이해하기 6] 꼭 알아야 할 쿠버네티스 주요 명령어
[쿠버네티스 쉽게 이해하기 7] 파드 실행 및 통제를 위한 워크로드 컨트롤러
[쿠버네티스 쉽게 이해하기 8] 파드 로드 밸런서 서비스
[쿠버네티스 쉽게 이해하기 9] 서비스 로드 밸런서 인그레스
[쿠버네티스 쉽게 이해하기 10] 환경변수 컨피그맵과 시크릿
[쿠버네티스 쉽게 이해하기 11] 데이터 저장소 사용을 위한 PV/PVC
[쿠버네티스 쉽게 이해하기 12] 헬스 체크를 위한 스타트업 프로브, 라이브니스 프로브, 레디니스 프로브
[쿠버네티스 쉽게 이해하기 13] 통합 로깅을 위한 EFK 스택
[쿠버네티스 쉽게 이해하기 14] 인증Authentication과 알백RBAC 방식의 인가Authorization
[쿠버네티스 쉽게 이해하기 15] 더 알면 좋을 주제들: 무중단 배포, 모니터링, HPA

댓글

전자책 출간 알림 [마이크로서비스패턴 쉽게 개발하기]