반응형

* 쿠버네티스 공식 문서에서 튜토리얼 진행하며 한국어로 번역하여 정리한 내용입니다.

* https://kubernetes.io/ko/docs/tutorials/ 에서 Katacoda를 사용하여 브라우저 상 터미널로 동일한 내용을 실습해 볼 수 있습니다.

목표 : 쿠버네티스에 두 개의 마이크로서비스를 배포하고, MicroProfile Config, 쿠버네티스 ConfigMap 및 Serect을 사용하여 구성 변경하기

- Step 1 : Build and Deploy the Java microservices

시작하기 위해서, 쿠버네티스 환경이 설정되어 있는지 확인하세요.

준비되었는지 확인하려면 다음 명령을 실행하세요.

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"20", GitVersion:"v1.20.4", GitCommit:"e87da0bd6e03ec3fea7933c4b5263d151aafd07c", GitTreeState:"clean", BuildDate:"2021-02-18T16:12:00Z", GoVersion:"go1.15.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"20", GitVersion:"v1.20.2", GitCommit:"faecb196815e248d3ecfb03c680a4507229c2a56", GitTreeState:"clean", BuildDate:"2021-01-13T13:20:00Z", GoVersion:"go1.15.5", Compiler:"gc", Platform:"linux/amd64"}

이제 제공된 프로젝트 디렉토리로 이동해야합니다.

$ cd sample-kubernetes-config/start/

여기에는 MicroProfile 마이크로서비스의 구현, MicroProfile 런타임을 위한 구성, 쿠버네티스 구성을 포함합니다.

참조용으로 이 튜토리얼의 완성된 코드를 포함하는 'finish' 디렉토리도 있습니다.

'system'과 'inventory'라는 두 개의 배포할 마이크로서비스가 있습니다.

$ ls -l
total 24
drwxr-xr-x 3 root root  4096 Oct 16 06:25 inventory
-rw-r--r-- 1 root root  1566 Oct 16 06:25 kubernetes.yaml
-rw-r--r-- 1 root root 10284 Oct 16 06:25 pom.xml
drwxr-xr-x 3 root root  4096 Oct 16 06:25 system

system 마이크로서비스는 실행 중인 컨테이너의 JVM 프로퍼티를 반환합니다.

inventory 마이크로서비스는 system 마이크로서비스의 프로퍼티를 invetory에 추가합니다.

이는 쿠버네티스 내부의 분리된 포드에 있는 두 개의 마이크로서비스 간에 어떻게 통신이 달성될 수 있는지 보여줍니다.

Maven으로 애플리케이션을 빌드하기 위해, 다음 명령을 차례대로 실행합니다.

$ mvn package -pl system
$ mvn package -pl inventory

서비스가 빌드되면, 쿠버네티스에 배포해야 합니다.

쿠버네티스 매니페스트에 대해 더 배우려면, 다음 문서를 참고하세요.

https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/

 

 

$ cat kubernetes.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: system-deployment
  labels:
    app: system
spec:
  selector:
    matchLabels:
      app: system
  template:
    metadata:
      labels:
        app: system
    spec:
      containers:
      - name: system-container
        image: system:1.0-SNAPSHOT
        ports:
        - containerPort: 9080
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 9080
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 3
          failureThreshold: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inventory-deployment
  labels:
    app: inventory
spec:
  selector:
    matchLabels:
      app: inventory
  template:
    metadata:
      labels:
        app: inventory
    spec:
      containers:
      - name: inventory-container
        image: inventory:1.0-SNAPSHOT
        ports:
        - containerPort: 9080
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 9080
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 3
          failureThreshold: 1
---
apiVersion: v1
kind: Service
metadata:
  name: system-service
spec:
  type: NodePort
  selector:
    app: system
  ports:
  - protocol: TCP
    port: 9080
    targetPort: 9080
    nodePort: 31000
---
apiVersion: v1
kind: Service
metadata:
  name: inventory-service
spec:
  type: NodePort
  selector:
    app: inventory
  ports:
  - protocol: TCP
    port: 9080
    targetPort: 9080
    nodePort: 32000

위와 같은 yaml 파일을 작성하고,

쿠버네티스에 배포하려면, 다음 명령어를 사용해줍니다.

$ kubectl apply -f kubernetes.yaml

 

 

- Step 2 : Configuring a Kubernetes Microservice

아래의 두 명령은 포드의 상태를 확인하고, 그것들이 언제 준비 상태에 있는지 확인합니다.

이것은 inventory와 같은 포드에 대한 레이블과 함께 명령을 제공하여 수행됩니다.

다음 명령을 실행해서 마이크로서비스의 상태를 확인하세요.

$ kubectl wait --for=condition=ready pod -l app=inventory
pod/inventory-deployment-67ffcfc8f6-nq4bq condition met
$ kubectl wait --for=condition=ready pod -l app=system
pod/system-deployment-85b9978c95-f4hpd condition met

각각의 위 명령에서 condition met이라는 출력이 나타나면, 마이크로서비스가 요청받을 준비가 되었다는 것을 의미합니다.

이제 마이크로서비스들이 배포되었고 Ready 상태로 실행 중이므로, 일부 요청을 보낼 준비가 되었습니다.

다음으로 system 서비스에 curl을 사용하여 HTTP GET 요청을 할 것입니다.

서비스는 요청에 전달된 사용자 id와 패스워드로 보호됩니다.

$ curl -u bob:bobpwd http://$( minikube ip ):31000/system/properties

실행 중인 컨테이너의 JVM 시스템 프로퍼티를 나타내는 응답이 표시되어야합니다.

(노드 포트는 kubectl describe service로 확인할 수 있습니다.)

마찬가지로, inventory 서비스를 호출하려면 다음 curl 명령어를 사용할 수 있습니다.

$ curl http://$( minikube ip ):32000/inventory/systems/system-service

인벤토리는 시스템 서비스를 호출하고, 결과를 반환하기 전에 인벤토리 서비스에 응답 데이터를 저장할 것입니다.

이 튜토리얼에서는, X-App-Name: 응답 헤더를 수정하기 위해, 쿠버네티스의 ConfigMap을 사용할 것입니다.

다음 curl 명령을 실행해서 현재 값을 살펴보세요.

$ curl -# -I -u bob:bobpwd -D - http://$( minikube ip ):31000/system/properties | grep -i ^X-App-Name:
X-App-Name: system
X-App-Name: system

 

 

- Step 3 : Modifying the System Microserivce

system 서비스는 app 이름으로 system을 가지도록 하드코딩 되어있습니다.

이를 구성하도록 하려면,

/sample-kubernetes-config/start/system/src/main/java/system/SystemResource.java 파일에 appName 멤버와 코드를 추가합니다.

package system;

// CDI
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
// JAX-RS
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.eclipse.microprofile.config.inject.ConfigProperty;

@RequestScoped
@Path("/properties")
public class SystemResource {

  @Inject
  @ConfigProperty(name = "APP_NAME")
  private String appName;

  @Inject
  @ConfigProperty(name = "HOSTNAME")
  private String hostname;

  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response getProperties() {
    return Response.ok(System.getProperties())
      .header("X-Pod-Name", hostname)
      .header("X-App-Name", appName)
      .build();
  }
}

이러한 변경 사항은 MicroProfile Config와 CDI를 사용하여 APP_NAME이라는 환경 변수 값을 SystemResource 클래스의 appName 멤버에 주입합니다.

MicroProfile Config는 환경 변수를 포함하여 구성을 수신할 다양한 config 소스를 지원합니다.

- Step 4 : Modifying the Inventory Microserivce

inventory 서비스는 system 서비스에 대해 인증하기 위한 자격 증명으로, bob과 bobpwd가 하드코딩 되어있습니다.

쿠버네티스 Secret으로 이러한 자격 증명을 구성할 수 있도록 만들 수 있습니다.

/sample-kubernetes-config/start/inventory/src/main/java/inventory/client/SystemClient.java 파일을 열어서,

//Basic Auth Credentials 밑에 두 줄을 다음 코드로 변환해줍니다.

  // Basic Auth Credentials
  @Inject
  @ConfigProperty(name = "SYSTEM_APP_USERNAME")
  private String username;

  @Inject
  @ConfigProperty(name = "SYSTEM_APP_PASSWORD")
  private String password;

이 변경 사항은 환경 변수 값 SYSTEM_APP_USERNAME과 SYSTEM_APP_PASSWORD를 SystemClient 클래스에 주입하기 위해 MicroProfile Config와 CDI를 사용합니다.

- Step 5 : Creating a ConfigMap and Secret

컨테이너에 환경 변수를 구성하기 위한 방법에는 여러가지가 있습니다.

이 값들을 설정하기 위해 쿠버네티스 ConfigMap과 Secret을 사용할 것입니다.

이는 쿠버네티스에 의해 제공되는 리소스이고, 컨테이너에 구성 값들을 제공하기 위한 방법으로 사용됩니다.

이점으로는, 다른 컨테이너에 대해 다른 환경 변수가 할당되는 것을 포함하여, 여러 개의 컨테이너에 걸쳐서 재사용될 수 있습니다.

다음 kubectl 명령으로 애플리케이션 이름을 구성하는 ConfigMap을 만들어봅시다.

$ kubectl create configmap sys-app-name --from-literal name=my-system

이 명령은 클러스터에 sys-app-name이라는 ConfigMap을 배포합니다.

name이라는 키와 my-system이라는 값을 가지고 있습니다.

--from-literal 플래그는 ConfigMap에 저장할 개별적인 key-value 쌍을 지정할 수 있습니다.

--from-file과 --form-env-file와 같이 다른 사용 가능한 옵션은, 다양한 구성 방법을 제공합니다.

이 옵션에 대한 세부사항은 쿠버네티스 CLI 문서에서 찾을 수 있습니다.

https://kubernetes.io/docs/concepts/configuration/configmap/

inventory 서비스가 system 서비스에 대해 인증하기 위한 자격 증명을 구성하기 위한 secret을,

다음 kubectl 명령어를 이용하여 만들어봅시다.

$ kubectl create secret generic sys-app-credentials --from-literal username=bob --from-literal password=bobpwd
secret/sys-app-credentials created

이 명령은 ConfigMap을 만드는 커맨드와 아주 유사하게 보이지만, 한 가지 다른점은 generic이라는 단어입니다.

그건 secret이 generic으로 만들어졌다는 것을 의미하고, 특별한 타입의 secret이 아니라는 것입니다.

Docker credentials을 저장하기 위한 secret, public/private key 쌍을 저장히기 위한 secret과 같은 다양한 타입의 secret이 있습니다.

secret은 자격 증명과 같은 민감한 정보에 사용된다는 것을 제외하고는, ConfigMap과 유사합니다.

주요 차이점 한 가지는, secret의 내용을 표시하도록 kubectl에 명시적으로 지시해야한다는 것입니다.

추가적으로, 정보가 보여질 때, 오직 Base64로 인코딩된 버전만 보이게 돼서, 평범한 구경꾼이 실수로 어떠한 민감한 데이터도 볼 수 없도록 합니다.

secret은 기본적으로 암호화를 제공하지 않기 때문에, 이를 직접 수행하거나 구성할 대체 옵션을 찾아야합니다.

- Step 6 : Updating Kubernetes resources

이제 ConfigMap과 Secret에서 구성된 값을 기반으로 컨테이너의 환경 변수를 설정하도록 쿠버네티스 deployment를 업데이트할 것입니다.

start 디렉토리에 위치한 kubernetes.yaml 파일을 수정합니다.

이 파일은 쿠버네티스 deployment를 정의합니다.

valueFrom 필드는 환경 변수의 값을 지정하며, 다양한 소스에서 설정될 수 있습니다.

소스에는 ConfigMap, Secret, 클러스터에 대한 정보가 포함됩니다.

이번 예시에서, configMapKeyRef는 ConfigMap의 sys-app-name이라는 값으로, 키 name을 설정합니다.

유사하게, secretKeyRef는 sys-app-credentials Secret으로 키 username과 password를 설정합니다.

/sample-kubernetes-config/start/kubernetes.yaml 파일을 열고, 다음 내용으로 변경합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: system-deployment
  labels:
    app: system
spec:
  selector:
    matchLabels:
      app: system
  template:
    metadata:
      labels:
        app: system
    spec:
      containers:
      - name: system-container
        image: system:1.0-SNAPSHOT
        ports:
        - containerPort: 9080
        # Set the APP_NAME environment variable
        env:
        - name: APP_NAME
          valueFrom:
            configMapKeyRef:
              name: sys-app-name
              key: name
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inventory-deployment
  labels:
    app: inventory
spec:
  selector:
    matchLabels:
      app: inventory
  template:
    metadata:
      labels:
        app: inventory
    spec:
      containers:
      - name: inventory-container
        image: inventory:1.0-SNAPSHOT
        ports:
        - containerPort: 9080
        # Set the SYSTEM_APP_USERNAME and SYSTEM_APP_PASSWORD environment variables
        env:
        - name: SYSTEM_APP_USERNAME
          valueFrom:
            secretKeyRef:
              name: sys-app-credentials
              key: username
        - name: SYSTEM_APP_PASSWORD
          valueFrom:
            secretKeyRef:
              name: sys-app-credentials
              key: password
---
apiVersion: v1
kind: Service
metadata:
  name: system-service
spec:
  type: NodePort
  selector:
    app: system
  ports:
  - protocol: TCP
    port: 9080
    targetPort: 9080
    nodePort: 31000
---
apiVersion: v1
kind: Service
metadata:
  name: inventory-service
spec:
  type: NodePort
  selector:
    app: inventory
  ports:
  - protocol: TCP
    port: 9080
    targetPort: 9080
    nodePort: 32000

 

 

- Step 7 : Deploying your changes

이제 변경 사항을 적용하려면, 애플리케이션을 다시 빌드하고 배포해야합니다.

start 디렉토리에서 다음 명령어를 사용하여 애플리케이션을 다시 빌드하겠습니다.

$ mvn package -pl system
$ mvn package -pl inventory

 

이제 다음 명령어를 실행해서, 이전 쿠버네티스 deployment를 삭제하고, 업데이트된 deployment를 배포하겠습니다.

$ kubectl replace --force -f kubernetes.yaml
deployment.apps "system-deployment" deleted
deployment.apps "inventory-deployment" deleted
service "system-service" deleted
service "inventory-service" deleted
deployment.apps/system-deployment replaced
deployment.apps/inventory-deployment replaced
service/system-service replaced
service/inventory-service replaced

 

서비스의 포드 상태를 확인해보겠습니다.

$ kubectl get --watch pods
NAME                                   READY   STATUS    RESTARTS   AGE
inventory-deployment-8b65548b9-mb6l8   1/1     Running   0          42s
kubernetes-bootcamp-fb5c67579-9q9n5    1/1     Running   0          24m
system-deployment-5f46847c5-wzqfl      1/1     Running   0          42s

결국 두 개의 서비스가 표시되어야 합니다. Ctrl-C를 눌러서 터미널 명령을 종료합니다.

curl 커맨드를 사용하여 업데이트된 system 서비스를 호출하고, 헤더를 확인해보겠습니다.

$ curl -# -I -u bob:bobpwd -D - http://$( minikube ip ):31000/system/properties | grep -i ^X-App-Name:
###=-#                                                              
X-App-Name: my-system
X-App-Name: my-system

응답의 X-App-Name 헤더가 system에서 my-system으로 변경된 것을 볼 수 있습니다.

다음 curl 요청을 보냄으로써, 자격 증명에 대해 쿠버네티스 Serect을 사용하여 inventory 서비스를 검증해보습니다.

$ curl http://$( minikube ip ):32000/inventory/systems/system-service
{"java.vendor":"AdoptOpenJDK","default.https.port":"9443","sun.java.launcher":
...

만약 요청이 실패한다면, Secret이 올바르게 구성되었는지 확인해보면 됩니다.

출처 : https://kubernetes.io/ko/docs/tutorials/configuration/configure-java-microservice/configure-java-microservice-interactive/ 

 

반응형

+ Recent posts