Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deployment of uEngine5 on Kubernetes #116

Open
jinyoung opened this issue Aug 27, 2018 · 2 comments
Open

Deployment of uEngine5 on Kubernetes #116

jinyoung opened this issue Aug 27, 2018 · 2 comments

Comments

@jinyoung
Copy link
Member

jinyoung commented Aug 27, 2018

Definition Service 의 Deploy

Docker image 업로드

git clone https://github.com/TheOpenCloudEngine/uEngine5-base.git
cd uEngine5-base/definition-service
mvn package -B
docker build -t gcr.io/uengine5-k8s-project/uengine-definition-service:v1 .
docker push gcr.io/uengine5-k8s-project/uengine-definition-service:v1

Deployment 만들기

$ nano deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: uengine-definition-deployment
  labels:
    app: uengine-definition
    group: uengine
spec:
  replicas: 3
  selector:
    matchLabels:
      app: uengine-definition
  template:
    metadata:
      labels:
        app: uengine-definition
        group: uengine
    spec:
      containers:
      - name: uengine-definition
        image: gcr.io/uengine5-k8s-project/uengine-definition-service:v1
        ports:
        - containerPort: 8080

Deploy 시키기

kubectl create -f deployment.yml
kubectl get pods # deploy 확인
(pod 3개 생성된 것 확인)
uengine-definition-deployment-79d484b99f-px4fk   1/1       Running            0          1m
uengine-definition-deployment-79d484b99f-qb5hj   1/1       Running            0          1m
uengine-definition-deployment-79d484b99f-tvnp9   1/1       Running            0          1m

Service 생성하기

$ nano service.yml 

apiVersion: v1
kind: Service
metadata:
  name: uengine-definition-svc
  labels:
    app: uengine-definition
    group: uengine
spec:
  type: LoadBalancer
  ports:
  - port: 8080
  selector:
    app: uengine-definition

$ kubectl create -f service.yml

$ kubectl get services   # 확인
NAME                     TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
eureka-svc               LoadBalancer   10.43.253.142   35.225.148.29   8080:30547/TCP   1h
kubernetes               ClusterIP      10.43.240.1     <none>          443/TCP          1d
uengine-definition-svc   LoadBalancer   10.43.242.217   35.232.6.115    8080:32248/TCP   2m 

웹브라우저를 하나 열어, 확인된 External-IP 인 35.232.6.115 에 8080 으로 접속하면 아래와 같이 서비스가 열린것을 확인 가능:

{
  "_links" : {
    "profile" : {
      "href" : "http://35.232.6.115:8080/profile"
    }
  }
}

[Note] 지금은 테스트를 위해 Definition Service 를 곧바로 LoadBalancer 로 바로 노출 시켜 인터넷에서 확인했지만 나중에 Zuul 로 포장하여 우회시키고 ClusterIP (내부 ip) 로만 서비스를 열 예정이다.

프로세스 정의의 deploy

$ http POST http://35.232.6.115:8080/definition/raw/folder/object1.json definition="Hello" 

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Date: Mon, 27 Aug 2018 03:15:13 GMT
Transfer-Encoding: chunked
X-Application-Context: definition:msa:8080

{
    "_links": {
        "instantiation": {
            "href": "http://35.232.6.115:8080/instance?defPath=/folder/object1.String.xml"
        }, 
        "raw": {
            "href": "http://35.232.6.115:8080/definition/raw//folder/object1.String.json"
        }, 
        "self": {
            "href": "http://35.232.6.115:8080/definition//folder/object1.String.xml"
        }
    }, 
    "directory": false, 
    "name": "object1.String.xml", 
    "path": "/folder/object1.String.xml"
}

그런데, Deployment 가 3개 있기 때문에 파일의 저장소가 각 인스턴스별 달라져서 External Ip 로 GET할때마다 있을때도 있고 없을때도 있다. 이 문제는 Replica 들이 동일한 저장소를 mount하도록 처리함으로서 해결할 수 있다 (continued)

Google Cloud Disk 의 mount

앞서 인스턴스간 파일 시스템 공유를 위한 작업으로 PersistenceVolume 과 PersistenceVolumeClaim 객체를 만든다:

$ nano pv.yml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-demo2
spec:
  storageClassName:
  capacity:
    storage: 20G
  accessModes:
    - ReadWriteOnce
  gcePersistentDisk:
    pdName: disk-2
    fsType: ext4

$ kubectl create -f pv.yaml

$ nano pvc.yaml

apiVersion: v1
kind : PersistentVolumeClaim
metadata:
  name: pv-claim-demo2
spec:
  storageClassName: ""
  volumeName: pv-demo2
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20G

$ kubectl create -f pvc.yml

각 Storage 는 gcloud 에서 미리 생성해두어야 한다. storage 생성방법은 아래와 같으며, project 와 동일한 region 에 생성시켜주야 한다.

gcloud compute disks create mydisk --size 100gb --type pd_standard

그런후, 생성한 PersistenceVolumeClaim 을 Deployment 내의 spec 란에 mount 시켜주면 된다.

$ nano deployment.yml
...
    spec:
      containers:
      - name: uengine-definition
        image: gcr.io/uengine5-k8s-project/uengine-definition-service:v1
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: storage       
          mountPath: /oce/repository
        volumes:
        - name: storage 
          persistentVolumeClaim:
            claimName: pv-claim-demo2

위와 같이 수정후, 반영:

kubectl apply -f deployment.yml

무정지 재배포

kubectl get pods
kubectl get deployments
kubectl set image deployment/uengine-definition-deployment uengine-definition=uengine-definition-service:v2  #container 명=registry:tag
kubectl rollout status deployment/uengine-definition-deployment
kubectl get deployments
kubectl get pods
kubectl describe pods (podname)

롤백

kubectl get pods
kubectl get deployments -o wide
kubectl rollout undo deployment/uengine-definition-deployment
kubectl get deployments -o wide

오토스케일링

kubectl autoscale deployment uengine-definition-deployment --cpu-percent=50 --min=1 --max=10

Availability 체크 통한 Self-Healing 관리


$ nano deployment.yml

...
    spec:
      containers:
...
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
          httpHeaders:
          - name: X-Custom-Header
            value: Awesome
        initialDelaySeconds: 3
        periodSeconds: 3

(저장후 quit)
kubectl apply -f ~/deployment.yml

Netflix OSS 적용하기

Registry 서비스 올리기

cd ~/
docker build -t gcr.io/uengine5-k8s-project/eureka:v1 .   #gcr.io 가 들어가면 goole registry 에 등록됨
docker push gcr.io/uengine5-k8s-project/eureka:v1

$ nano deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: eureka-deployment
  labels:
    app: eureka
spec:
  replicas: 3
  selector:
    matchLabels:
      app: eureka
  template:
    metadata:
      labels:
        app: eureka
    spec:
      containers:
      - name: eureka
        image: gcr.io/uengine5-k8s-project/eureka:v1     #전체 주소를 주야 함.
      ports:
        - containerPort: 8741    # 8741 로 내부에서 오픈했다...

(kubectl delete deployments -l app=eureka  # 지울일이 있다면.. 그러나 정지상태를 노출할 수 있으니 테스트 때만 사용하고, 운영때는 apply -f 나 image change 를 하는걸 추천)
kubectl apply -f deployment.yml
kubectl get pods
kubectl describe pod eureka-deployment-7cddf689df-hxvzh    #pod가 일단 잘 디플로이 됐는지 확인

서비스(LoadBalancer) 등록 통한 외부노출

apiVersion: v1
kind: Service
metadata:
  name: eureka-svc
  labels:
    app: eureka
spec:
  ports:
  - port: 27017
    protocol: TCP
  selector:
    app: eureka

Registry 서비스의 주소는 환경변수를 통하여 각 서비스에 전파시켜야 하는데, Kubernetes 에서는 각 서비스들의 주소를 전달하는 체계로 환경변수 혹은 내부 DNS 를 사용한다. 환경 변수는 유레카가 내려갔다 올라올때 전체 서비스의 재기동을 야기할 수 있으므로, 여기서는 내부 DNS를 사용하는게 좋다:

$ nano  src/main/resources/application.yml

... dev, stg, prod 에 해당하는 profile 에서 설정 ..

eureka:
  client:
    serviceUrl:
      defaultZone: http://eureka-svc.default.svc.cluster.local:8761/eureka/     #서비스명.네임스페이스명(기본은 default).svc.cluster.local 로 접근가능하다.

설정을 먹히게 하기 위해 1. 메이븐빌드, 2. 도커빌드, 3. 레지스트리 푸시, 4. 쿠버 desired state 변경을 아래와 같이 수행한다:

mvn package -B
docker build -t gcr.io/uengine5-k8s-project/uengine-definition-service:v2 .  # 버전업
docker push gcr.io/uengine5-k8s-project/uengine-definition-service:v2
nano deployment.yml
 (image 를 gcr.io/uengine5-k8s-project/uengine-definition-service:v2 로 변경 후 저장)
kubectl apply -f deployment.yml

[Tip] 환경 변수로 혹시 전달을 해야 하는 경우라면, 다음과 같이 모든 서비스들의 주소는 아래처럼 container 내부의 환경 변수로 전달됨을 확인할 수 있으므로, "Service명_HOST" 를 통하여 얻어낸 후 애플리케이션에 전달해주면 된다.

$ kubectl exec -it uengine-definition-deployment-79d484b99f-px4fk -- /bin/sh
/ # export
export CI_COMMIT_SHA=''
export CI_PROJECT_NAME=''
export EUREKA_SVC_PORT='tcp://10.43.253.142:8080'
export EUREKA_SVC_PORT_8080_TCP='tcp://10.43.253.142:8080'
export EUREKA_SVC_PORT_8080_TCP_ADDR='10.43.253.142'
export EUREKA_SVC_PORT_8080_TCP_PORT='8080'
export EUREKA_SVC_PORT_8080_TCP_PROTO='tcp'
export EUREKA_SVC_SERVICE_HOST='10.43.253.142'
export EUREKA_SVC_SERVICE_PORT='8080'
export HOME='/root'
export HOSTNAME='uengine-definition-deployment-79d484b99f-px4fk'
export JAVA_ALPINE_VERSION='8.111.14-r0'
export JAVA_HOME='/usr/lib/jvm/java-1.8-openjdk'
export JAVA_VERSION='8u111'
export KUBERNETES_PORT='tcp://10.43.240.1:443'
export KUBERNETES_PORT_443_TCP='tcp://10.43.240.1:443'
export KUBERNETES_PORT_443_TCP_ADDR='10.43.240.1'
export KUBERNETES_PORT_443_TCP_PORT='443'
export KUBERNETES_PORT_443_TCP_PROTO='tcp'
export KUBERNETES_SERVICE_HOST='10.43.240.1'
export KUBERNETES_SERVICE_PORT='443'
export KUBERNETES_SERVICE_PORT_HTTPS='443'
export LANG='C.UTF-8'
export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin'
export PWD='/'
export SHLVL='1'
export TERM='xterm'
@jinyoung
Copy link
Member Author

jinyoung commented Aug 27, 2018

Todos

  1. eureka 에 등록이 안되는 이유 확인 : 유레카 api 를 각 container 내에서 직접 호출해봐야 알 수 있을듯..
  2. zuul 로 연결, zuul 을 LoadBalancer 를 통해 open
  3. zuul 을 ingress 로 변경 - 변경에 의미가 있는가? 성능상 이점. 변경시 발생하는 문제, 유레카에 등록된 serviceId 를 첫번째 path 요소로 하여 자동 라우팅 되던 것이 ingress 에선 어떻게 되는가?
  4. 제대로 rollout 과 deploy 가 안되는거 같다... (disk mount 설정이 어떤 컨테이너에만 반영되어 있는 상황 발견)
  5. 프로메테우스로 로그 수집해서 볼 수 있는 환경 구축 필요함
  6. Spinnaker 혹은 gitlab과 연계
  7. 계정별 접근 권한 처리

@jinyoung jinyoung changed the title Kubernetes Deployment of uEngine5 Deployment of uEngine5 on Kubernetes Aug 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant