4. 매니페스트 작성 및 웹 모듈 실행

소개



본 기사는 이하 3의 계속입니다.
1. Google Kubernetes Engine(GKE)에서 Java 웹 모듈을 빠르게 실행해 보세요.
2. Docker 이미지 생성 및 레지스트리 등록
3. 웹 모듈에서 액세스하는 데이터베이스 만들기
4. 매니페스트 작성 및 웹 모듈 실행

4-1. 매니페스트 작성 및 웹 모듈 실행



절차 4-1.1



GKE에 앱(이번에는 웹 모듈)을 배포하는 데 필요한 매니페스트 파일을 만듭니다.
vi를 시작하고 다음 내용으로 sample-app_dev.yaml을 만듭니다.
※2개소 있는 [project_id]는 각자의 환경에 맞추어 잊지 않고 다시 써 주세요.
[userid]@cloudshell:~ ([project_id])$ vi sample-app_dev.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  # Deploymentの名前。namespace内ではユニークである必要があります
  name: sample-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample-app
  # PodがReady状態になってから使用可能な状態になるまでの待ち時間を指定する。
  # デフォルトは0秒です。なので指定をしないと即座に使用可能な状態として扱われる。
  minReadySeconds: 5

  # Deploymentの処理の最大処理時間を指定する。
  # Deploymentの処理時間がこの時間を超えた場合
  # 処理を失敗させProgressDeadlineExceededをstatusにセットし、自動でロールバックされます。
  # デフォルトは600秒です。
  progressDeadlineSeconds: 600

  strategy:
    # ローリングアップデートを実行
    type: RollingUpdate

    rollingUpdate:
      # 現在起動しているPod数に対してアップデート時にどの程度までの減少(スケールイン)を許すか。
      # 例えば現在2台のPodが起動しており、maxUnavailable=50%(もしくは1)を設定した場合
      # アップデートに伴い2台中1台のPodは利用不可となることを許可します。
      maxUnavailable: 50%

      # アップデート時に現在起動しているPod数に対してどの程度までの増加(スケールアウト)を許すか。
      # 例えば現在2台のPodが起動しており、maxSurge=50%(もしくは1)を設定した場合、アップデートに伴いPod1台までのスケールアウトは許可します。
      # つまりアップデート中は旧バージョン含め合計3台までであればPodの起動を許可することになります。
      maxSurge: 50%

  # この部分がPodのTemlate。ここの記述内容に変更があったときローリングアップデートが起こる
  template:
    metadata:
      labels:
        # ラベル指定は必須 spec.selector.matchLabelsと合わせる必要がある
        app: sample-app
    spec:
      containers:
        - name: sample-app-container
          image: gcr.io/[project_id]/sample-app:latest

          ports:
            - containerPort: 8080
              name: api-port
              protocol: TCP

          # 正常に起動しているかの確認。ヘルスチェック失敗時にはPodを再起動します。
          # initialDelaySecondsはアプリを起動してから何秒後にヘルスチェックを始めるかを示している。
          # 例えば、起動するまで時間かかるようなアプリケーションだとこの設定を指定すると便利。
          # timeoutSecondsはヘルスチェックのレスポンスを何秒待つかを示す。livenessProbeの場合はこれをできるだけ短くしたほうが早く検知するので復活が速い。
          # でも注意すべき点があって負荷がかかっている状態でも適切なタイムアウトを設定しないと
          # 一番忙しい時なのにアプリが再起動されてしまったり、パフォーマンスに影響がでる。なので、適切なtimeoutSecondsを指定するのが大事。
          # アプリケーションのlivenessProbeに接続できなかったり、HTTPエラーコードが返ってきた場合
          # periodSecondsは定期実行のスケジュール。
          # failureThresholdは指定値の失敗でコンテナ再起動を行う。
          livenessProbe:
            httpGet:
              scheme: HTTP
              path: /sample-app/views/NewFile.jsp
              port: api-port

            initialDelaySeconds: 10
            timeoutSeconds: 5
            periodSeconds: 30
            failureThreshold: 20

          # Podがサービスイン出来ているかの確認。ヘルスチェック失敗時にはトラフィックを流さない(Podの再起動はしない)。
          # readinessProbeが失敗した場合、そのPodがサービスのエンドポイントから外される。
          # 例えばローリングアップデートの時や、スケールアップした時、新しいPodが機能されていたんだけど
          # まだトラフィック受けられないタイミングでリクエストが来たら、困るのでreadinessProbeでそういうことを防ぐ。
          readinessProbe:
            httpGet:
              scheme: HTTP
              path: /sample-app/servlet/MyServlet
              port: api-port

            initialDelaySeconds: 10
            timeoutSeconds: 5
            periodSeconds: 60
            failureThreshold: 5

          resources:
            # Podをデプロイする時に必要とするリソース(CPU/メモリ)を指定する。
            # ただしPodは指定したresource requests以上のリソースを使うことができる。(リソース使用量の制限はlimitを使う)
            # ポイントとしてはPodをデプロイするときに、nodeのリソース使用量は見ないでresource requestsをみてデプロイが行われる。
            # cpu 200m は200 millicoresの略で1000milli coreで1cpu。
            # 200 mill coreで 1/5 CPU使うということ。(ちなみにcpu: 1と指定したらcpu: 1000mと解釈される)
            # 500Miは 500mebibytes。
            requests:
              memory: "500Mi"

            # Podが使用するリソース(CPU/メモリ)に制限を設けることができる。
            # たとえnodeにリソースの空きがあっても指定されたresource limits以上のリソースは使用することができなくなる。
            # resource limitsを指定しない場合、無制限にリソースを使用できる。
            # resource requestsを指定していなかったら、limit値と同様の値がresource requestsに設定される。
            limits:
              memory: "600Mi"

          # 環境変数にデータベースホストとPostgreSQLインスタンスに
          # 接続するためのユーザーとパスワードを設定します。
          # cloud sql proxy経由でデータベースに接続するのでデータベースホストにはループバックアドレスを指定している。
          env:
            - name: POSTGRES_DB_HOST
              value: 127.0.0.1:5432
            # [START cloudsql_secrets]
            # 記事3で作成したsecretのusernameとpasswordを使用する
            - name: POSTGRES_DB_USER
              valueFrom:
                secretKeyRef:
                  name: cloudsql-db-credentials
                  key: username
            - name: POSTGRES_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: cloudsql-db-credentials
                  key: password
            # [END cloudsql_secrets]

        # [START proxy_container]
        - name: cloudsql-proxy
          image: gcr.io/cloudsql-docker/gce-proxy:1.13
          # 記事3で作成したsecretのサービスアカウントでデータベースとのプロキシを開始する
          command: ["/cloud_sql_proxy",
                    "-instances=[project_id]:us-central1:sample-app-ist=tcp:5432",
                    "-credential_file=/secrets/cloudsql/credentials.json"]
          # [START cloudsql_security_context]
          securityContext:
            runAsUser: 2  # non-root user
            allowPrivilegeEscalation: false
          # [END cloudsql_security_context]
          # 記事3で作成したsecretのサービスアカウントをマウントする
          volumeMounts:
            - name: cloudsql-instance-credentials
              mountPath: /secrets/cloudsql
              readOnly: true
        # [END proxy_container]

      # Podのシャットダウンプロセスが始まってからSIGKILLが送られるまでの時間です。
      # preStopの設定を入れている場合は、preStop処理が終了後にSIGTERMが送られ
      # シャットダウンプロセスが始まってからterminationGracePeriodSecondsで指定した秒数が経過してもプロセスが完了していない場合にはSIGLKILLが送られます。
      # デフォルトは30秒となっているはずです。
      terminationGracePeriodSeconds: 30

      # [START volumes]
      volumes:
        - name: cloudsql-instance-credentials
          secret:
            secretName: cloudsql-instance-credentials
      # [END volumes]

절차 4-1.2



만든 매니페스트 파일을 실행합니다.
안전하고 create되었습니다.
[userid]@cloudshell:~ ([project_id])$ kubectl apply -f sample-app_dev.yaml --record
deployment.apps "sample-app" created

절차 4-1.3



잠시 후 다음 명령으로 Pod가 성공적으로 시작되었는지 확인합니다.
READY가 2/2로 되어 ​​있으면 정상적으로 2개의 컨테이너가 기동하고 있습니다.
[userid]@cloudshell:~ ([project_id])$ kubectl get pods -o wide
NAME                       READY     STATUS    RESTARTS   AGE       IP           NODE
[pod_name]                 2/2       Running   0          40s       10.40.1.10   [node_name]

절차 4-1.4



성공적으로 시작되지 않은 경우 다음 명령을 사용하여 컨테이너 로그를 확인합니다. 다음은 sample-app-container 및 cloudsql-proxy 컨테이너가 성공적으로 시작된 경우의 로그입니다.
[userid]@cloudshell:~ ([project_id])$ kubectl logs [pod_name] -c sample-app-container
                 ・
                 ・
                 ・
12-Mar-2019 12:02:50.933 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
12-Mar-2019 12:02:50.935 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.16]
12-Mar-2019 12:02:50.960 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/apache-tomcat-9.0.16/webapps/sample-app]
12-Mar-2019 12:02:52.609 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
12-Mar-2019 12:02:52.705 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/apache-tomcat-9.0.16/webapps/sample-app] has finished in [1,744] ms
12-Mar-2019 12:02:52.714 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
12-Mar-2019 12:02:52.786 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
12-Mar-2019 12:02:52.817 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [2,069] milliseconds
[userid]@cloudshell:~ ([project_id])$ kubectl logs [pod_name] -c cloudsql-proxy
2019/03/12 11:55:17 current FDs rlimit set to 1048576, wanted limit is 8500. Nothing to do here.
2019/03/12 11:55:17 using credential file for authentication; email=sample-app-db-client@[project_id].iam.gserviceaccount.com
2019/03/12 11:55:17 Listening on 127.0.0.1:5432 for [project_id]:us-central1:sample-app-ist
2019/03/12 11:55:17 Ready for new connections

절차 4-1.5



인터넷에서 방금 시작한 포드에 액세스할 수 있도록 서비스를 정의한 매니페스트를 만듭니다.
[userid]@cloudshell:~ ([project_id])$ vi sample-app_svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: sample-app-svc
  namespace: default
spec:
  selector:
    app: sample-app
  type:
    LoadBalancer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

절차 4-1.6



서비스를 즉시 정의한 매니페스트를 실행합니다.
[userid]@cloudshell:~ ([project_id])$ kubectl apply -f sample-app_svc.yaml
service "sample-app-svc" created

절차 4-1.7



잠시 후 다음 명령을 사용하여 sample-app-svc의 EXTERNAL-IP를 확인합니다.
[userid]@cloudshell:~ ([project_id])$ kubectl get service
NAME             TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes       ClusterIP      xxx.xxx.xxx.xxx     <none>        443/TCP        3d
sample-app-svc   LoadBalancer   yyy.yyy.yyy.yyy   zzz.zzz.zzz.zzz   80:31004/TCP   3m

절차 4-1.8



다른 브라우저를 실행하여 방금전의 EXTERNAL-IP로 아래의 URL을 표시시켜 봅시다. 현재 날짜와 시간과 테이블의 내용이 표시됩니다.

http://zzz.zzz.zzz.zzz/sample-app/views/NewFile.jsp


http://zzz.zzz.zzz.zzz/sample-app/servlet/MyServlet


결론



참고 문헌은 다음과 같습니다.
Kubernetes 완전 가이드 - 아오야마 신야 (저자)
Docker/Kubernetes 실습 컨테이너 개발 입문 - 야마다 아키노리 (저)
이상

좋은 웹페이지 즐겨찾기