Help us understand the problem. What is going on with this article?

今度はあんまりゴツくない!?「わりとゴツいKubernetesハンズオン」そのあとに

1月半ほど前、社内勉強会のおすそ分けとして、わりとゴツいKubernetesハンズオンの記事を書きました。
おかげさまでご好評いただき、今では1500を超えるいいねをいただきました。ありがとうございます。

今回の話とは全然関係ないですが、こちらも頑張って書いているので興味あれば見てやってください。
(マイナーなタグしか付けられなかったせいか、view数がとても少なくて悲しみに暮れています…😢)
QRコード Deep Dive ーデータ符号化とか誤り訂正とかー

開発環境の構築ができるようになろう!

さて、みなさまKubernetesについては完全理解しましたでしょうか?
主要な要素の説明はしているので、完全理解フェーズにたどり着くのも夢ではないと思います。

ただ、ハンズオンの中では、既存のDockerイメージしか使っていません。
スクリーンショット 2019-07-01 9.38.35.png

Kubernetesを使ってオリジナルのアプリケーションを構築するには、
Dockerを交えた開発環境の構築という、もうひと山を超えねばなりません。

ここで、前回のハンズオンの目標を見返してみてください。

  • 構築・運用ができるような気分になる

できるようになるとは言ってない…!(どーん

ということで、前回入れようと思ったけど力尽きたゴツくなりすぎると思ってやめておいた、
開発環境の構築について、またハンズオン形式でお伝えしようと思います!

ちなみに、本記事は福岡のKubernetes勉強会「ふくばねてす node-2」での発表資料をQiita用にコンバートしたものです。
発表資料 : https://speakerdeck.com/ktam1219/waritogotuikuberneteshanzuon-sofalseatoni

やりたいこと

ローカル開発環境

まずはローカルでの開発環境を作らないことには始まりません。
大まかな開発フローは以下の繰り返しになります。
1. コードを編集
2. Dockerイメージをbuild
3. ローカルのKubernetesクラスターにデプロイ
スクリーンショット 2019-07-01 9.39.50.png

CI/CD環境

本番環境にリリースする際の作業はさらに手順が増えます。
1. コードを編集
2. GitにPush
3. Dockerイメージをbuild
4. コンテナレジストリにDockerイメージをPush
5. Kubernetesクラスターにデプロイ
スクリーンショット 2019-07-01 9.40.08.png

手作業でやろうとすると大変なので、CircleCIなどを使って自動化したいですね。

以上が今回やりたいことなんですが、
なんだか一気にめんどくさい気持ちになってきましたね。

でも、簡単にできるんです。
そう、Skaffoldならね!

Skaffold

Skaffoldは、Google謹製のKubernetesの開発支援ツールです。
クラスタにアプリケーションをデプロイするまでの
一連の作業を(ローカル/リモート問わず)自動化してくれます。

  • Dockerイメージのbuild
  • Dockerイメージの構造テスト
  • Dockerイメージへのタグ付け
  • コンテナレジストリにDockerイメージをPush
  • KubernetesクラスタにDeploy

先ほど挙げたやりたいことに加え、テストやタグ付けまで…!

また、各フェーズは独立していて、プラグイン的にお好みでやり方を選択できます。
architecture.png

Skaffoldをローカル開発で使ってみよう

ローカルのKubernetes環境を準備する

前回のハンズオンを参考に、下準備の部分まで終わらせます。
https://qiita.com/Kta-M/items/ce475c0063d3d3f36d5d#kubernetes%E3%82%92%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86

サンプルアプリケーションを準備する

前回と同様、kubernetes/examplesのguestbookアプリを使いましょう。

$ git clone git@github.com:kubernetes/examples.git
$ mkdir skaffold_example
$ cp -R examples/guestbook/* skaffold_example
$ cd skaffold_example

不要なファイルを削除しておきます。

$ rm -rf all-in-one
$ rm -rf legacy

PCの負担を下げるためちょっと調整 & Dockerイメージの取得先を変更します。

$ vi examples/guestbook/frontend-deployment.yaml
10行目   replicas: 3 <- これを1に変更
19行目   image: gcr.io/google-samples/gb-frontend:v4 <- これを ${dockerhubのユーザー名}/skaffold-example-frontendに変更

$ vi examples/guestbook/redis-slave-deployment.yaml
11行目   replicas: 2 <- これを1に変更
21行目   image: gcr.io/google_samples/gb-redisslave:v1 <- これを ${dockerhubのユーザー名}/skaffold-example-redis-slaveに変更

ingressのマニフェストファイルを作成します。

$ cat << 'EOT' >./guestbook-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: guestbook-ingress
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: frontend
          servicePort: 80
EOT

Skaffoldのインストール & セットアップ

以下のURLを参考にインストールを行います。
https://skaffold.dev/docs/getting-started/#installing-skaffold

macであればHomebrewで入ります。

$ brew install skaffold

Skaffoldの設定ファイルを作成します。

skaffold.yaml
apiVersion: skaffold/v1beta11
kind: Config

# Dockerイメージのビルドに関する設定
build:
  artifacts:
  # ビルドするイメージ
  - image: ${dockerhubのユーザー名}/skaffold-example-frontend
    context: php-redis                                            # ソースファイルがあるパスの指定
  - image: ${dockerhubのユーザー名}/skaffold-example-redis-slave
    context: redis-slave
  local:                                                          # ローカルでイメージをビルドするときの設定
    push: false                                                   # ビルドしたイメージをpushするか

# デプロイに関する設定
deploy:
  kubectl:
     # デプロイ対象のマニフェストファイルの指定
    manifests:
    - frontend-*.yaml
    - redis-master-*.yaml
    - redis-slave-*.yaml
    - guestbook-ingress.yaml

設定ファイルのその他の項目については、以下を参照してください。いろいろできます。
https://skaffold.dev/docs/references/yaml/

skaffold dev

さて、ここで以下のコマンドを実行してみましょう。

$ skaffold dev

開発用のコマンドです。
実行後、Dockerイメージのビルド、Kubernetesクラスターへのデプロイをおこないます。
その後はファイルの変更を監視して、変更があるたびにビルド、デプロイを繰り返します。
また、ファイル変更監視中は、各Podのログも流してくれます。いたれりつくせり。

Generating tags...
 - mohri1219/skaffold-example-frontend -> mohri1219/skaffold-example-frontend:76a6cd0-dirty
 - mohri1219/skaffold-example-redis-slave -> mohri1219/skaffold-example-redis-slave:76a6cd0
Tags generated in 49.700092ms
Starting build...
Found [docker-for-desktop] context, using local docker daemon.
Building [mohri1219/skaffold-example-frontend]...
Sending build context to Docker daemon   7.68kB
Step 1/8 : FROM php:5-apache
 ---> 24c791995c1e

(中略)

Starting deploy...
kubectl client version: 1.14
deployment.apps/frontend created
service/frontend created
ingress.extensions/guestbook-ingress created
deployment.apps/redis-master created
service/redis-master created
deployment.apps/redis-slave created
service/redis-slave created

(中略)

Watching for changes every 1s...
[frontend-7df8f8b7f8-mscxk php-redis] AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.1.1.154. Set the 'ServerName' directive globally to suppress this message

前回のハンズオン同様、http://localhost にアクセスすると画面が出てきます。
スクリーンショット 2019-07-01 15.30.49.png

ファイルの変更検知機能を試してみるために、おもむろにhtmlファイルを書き換えてみます。

php-redis/index.html
<h2>Guestbook!!</h2>   <!- "!!"を追加してみる -->

すると、ちゃんと変更を検知してDockerイメージのビルドを始めてくれます!

Generating tags...
 - mohri1219/skaffold-example-frontend -> mohri1219/skaffold-example-frontend:76a6cd0-dirty
Tags generated in 62.953504ms
Starting build...
Found [docker-for-desktop] context, using local docker daemon.
Building [mohri1219/skaffold-example-frontend]...
Sending build context to Docker daemon   7.68kB
Step 1/8 : FROM php:5-apache
 ---> 24c791995c1e
Step 2/8 : RUN pear channel-discover pear.nrk.io
 ---> Using cache
 ---> bd9823d8109d
Step 3/8 : RUN pear install nrk/Predis
 ---> Using cache
 ---> 390dd33a211f

ブラウザをリロードしてみるとちゃんと変更が反映されていることが確認できます。
スクリーンショット 2019-07-01 15.30.57.png

最後に、Ctrl+Cで終了してみましょう
すると、DockerイメージやKubernetesクラスター内の各種リソースを削除してくれます!

Pruning images...
untagged image mohri1219/skaffold-example-frontend:3eba4d84484d6648b4a0907db8f472e5df4439d9ba4ca012a5b96f95af4dd09b
untagged image mohri1219/skaffold-example-frontend:c4971ec-dirty
untagged image mohri1219/skaffold-example-frontend@sha256:c2f8eb06b6a9d0624c1f8ea6cba4dfaefa450f11d99c90a209617618b0687730
deleted image sha256:3eba4d84484d6648b4a0907db8f472e5df4439d9ba4ca012a5b96f95af4dd09b
deleted image sha256:42794d3d5de90049ae108429e1536b747b145918b9972edd62e958b58b09c1ec
WARN[0290] builder cleanup: pruning images: Error response from daemon: conflict: unable to delete 48d1ae3a57c7 (cannot be forced) - image is being used by running container 0b0107ee518b
Cleaning up...
deployment.apps "frontend" deleted
service "frontend" deleted
ingress.extensions "guestbook-ingress" deleted
deployment.apps "redis-master" deleted
service "redis-master" deleted
deployment.apps "redis-slave" deleted
service "redis-slave" deleted
Cleanup complete in 3.70313407s

skaffold run

さて、次は以下のコマンドを実行してみましょう。

$ skaffold run

これは単発のデプロイコマンドで、Dockerイメージのビルド、Kubernetesクラスターへのデプロイをおこなって終了します。
終了後も各種リソースはKubernetesクラスター内に残り続けます。

Generating tags...
 - mohri1219/skaffold-example-frontend -> mohri1219/skaffold-example-frontend:76a6cd0-dirty
 - mohri1219/skaffold-example-redis-slave -> mohri1219/skaffold-example-redis-slave:76a6cd0
Tags generated in 48.802686ms
Starting build...
Found [docker-for-desktop] context, using local docker daemon.
Building [mohri1219/skaffold-example-frontend]...
Sending build context to Docker daemon   7.68kB
Step 1/8 : FROM php:5-apache
 ---> 24c791995c1e

(中略)

Starting deploy...
kubectl client version: 1.14
deployment.apps/frontend created
service/frontend created
ingress.extensions/guestbook-ingress created
deployment.apps/redis-master created
service/redis-master created
deployment.apps/redis-slave created
service/redis-slave created
Deploy complete in 1.763257066s

Skaffoldでテストもしてみる

Skaffoldのテストは、container-structure-testを使います。
その名の通り、コンテナイメージの構造をテストするものです。

できることは、

  • イメージ内のコマンドの出力をチェック
  • ファイルシステムのメタデータと内容を検証
  • etc...

今回は、skaffold-example-frontendのファイル存在チェックをしてみましょう。
その他のテスト項目については
https://github.com/GoogleContainerTools/container-structure-test/blob/master/README.md を参照してください。

structure-test/frontend.yaml
schemaVersion: 2.0.0

# 各種ファイルの存在確認
fileExistenceTests:
  - name: 'php file'
    path: '/var/www/html/guestbook.php'
    shouldExist: true
  - name: 'js file'
    path: '/var/www/html/controllers.js'
    shouldExist: true
  - name: 'html file'
    path: '/var/www/html/index.html'
    shouldExist: true

skaffoldの設定ファイルにテストの設定を追記しましょう。

skaffold.yaml
apiVersion: skaffold/v1beta11
kind: Config

build:
  (略)

# テストの設定
test:
  test:
  - image: ${dockerhubのユーザー名}/skaffold-example-frontend
    structureTests:
      - ./structure-test/frontend.yaml

deploy:
  (略)

skaffold runを実行すると、以下のようにログが出てきます。
もちろん、テストが失敗するとデプロイはされません。

$  skaffold run

(中略)

Starting test...

======================================
====== Test file: frontend.yaml ======
======================================
=== RUN: File Existence Test: php file
--- PASS

=== RUN: File Existence Test: js file
--- PASS

=== RUN: File Existence Test: html file
--- PASS


=======================================
=============== RESULTS ===============
=======================================
Passes:      3
Failures:    0
Total tests: 3

PASS
Test complete in 1.455478421s

お片付け

ローカルの開発環境についてはここまで。開発が進められるイメージは持てましたか?

Docker for DesktopのKubernetesを無効化してお片付けをしましょう。
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f33393536352f39373362343665662d636637652d616437352d623734352d6332666363653339353838652e706e67.png

SkaffoldをCI/CD向けに使ってみよう

完成版はこちらにあります。
https://github.com/Kta-M/skaffold_example

GitHubのリポジトリを作成

みんなできるだろうから割愛します。

DockerHubのリポジトリを作成

DockerHubも画面からリポジトリが作れます。
screencapture-cloud-docker-u-mohri1219-repository-create-2019-06-29-07_08_27.png

EKSでクラスタを作成

前回のハンズオンでやったやつです。
相変わらず立てるのに15分ぐらいかかります。とてもつらい。

$ eksctl create cluster \
  --name eksctl-handson \
  --region ap-northeast-1 \
  --nodes 3 \
  --nodes-min 3 \
  --nodes-max 3 \
  --node-type t2.medium \
  --ssh-public-key <キーペア名>

ap-northeast-1bが選択できる古いAWSアカウントはAZ指定行なってください。

Skaffoldの設定ファイルを調整

先ほどまでローカルでskaffoldを使ってきましたが、本番環境にデプロイする際は以下の点を変えたいです。

  • DockerイメージをコンテナレジストリにPushする
  • ingressのマニフェストファイルは使わない

こういった、状況に応じて挙動を切り替えるための仕組みとして、profileという機能があります。
実行時にprofileを与えると、それに応じた設定をオーバーライドしてくれる機能です。

skaffold.yaml
apiVersion: skaffold/v1beta11
kind: Config

(中略)

# 以下を追加
profiles:
- name: prd
  build:
    local:
      push: true                    # ビルドしたイメージをコンテナレジストリにPushする
  deploy:
    kubectl:
      manifests:                    # ingressのファイルを除外
      - frontend-*.yaml
      - redis-master-*.yaml
      - redis-slave-*.yaml

以下のようにprdのprofileを追記しましょう。
こうすることで、 skaffold run --profile prdとすればprdの設定でオーバーライドしてくれるようになります。

CircleCIの設定

CirlceCIにログインし、GitHubリポジトリを登録しましょう。
スクリーンショット 2019-06-29 6.47.58.png
screencapture-circleci-setup-project-gh-Kta-M-skaffold-example-2019-06-29-06_48_44.png

プロジェクト環境変数を設定します。
screencapture-circleci-gh-Kta-M-skaffold-example-edit-2019-06-30-17_48_07.png

変数名
AWS_DEFAULT_REGION ap-northeast-1
CUSTER_NAME eksctl-handson
DOCKER_HUB_USR DockerHubのユーザー名
DOCKER_HUB_PSW DockerHubのパスワードをbase64エンコードしたもの

EKSにデプロイするため、AWSの認証情報を設定します。
ここで、EKSクラスタを立てるのに使ったIAMユーザーと同じものを設定しなければならないことに注意してください。
KubernetesのRBACとIAMが紐付いてしまうので。
参考: https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/managing-auth.html
screencapture-circleci-gh-Kta-M-skaffold-example-edit-2019-06-30-17_58_50.png

また、orbを使えと言われてるけど今回は無視します。
orbはバージョン2.1でしか使えないけど、2.1はまだローカルでの動作確認ができないようなので…。とてもつらい。

CircleCIのconfigを作成

以下のようになります。nameを見ていけば何をしているのかだいたい分かるかと思います。
本来は、もろもろインストールしたDockerイメージを作ってからやるべきなんでしょうけど、
分かりやすくするためインストールもcircleciで行っています。

circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: docker:18.09
    steps:
    - run:
        name: set shell and install tools
        command: |
          set -x; \
          apk add --no-cache --virtual .fetch-deps curl git python py-pip less groff

    - checkout
    - setup_remote_docker

    - run:
        name: install kubectl
        command: |
          curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/linux/amd64/kubectl && \
          chmod +x ./kubectl && \
          mv ./kubectl /usr/local/bin/kubectl

    - run:
        name: install container-structure-test
        command: |
          curl -LO https://storage.googleapis.com/container-structure-test/latest/container-structure-test-linux-amd64 && \
          chmod +x container-structure-test-linux-amd64 && \
          mv container-structure-test-linux-amd64 /usr/local/bin/container-structure-test

    - run:
        name: install aws cli
        command: pip install awscli

    - run:
        name: install aws-iam-authenticator
        command: |
          curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.12.7/2019-03-27/bin/linux/amd64/aws-iam-authenticator && \
          chmod +x ./aws-iam-authenticator && \
          mv ./aws-iam-authenticator /usr/local/bin

    - run:
        name: setup kubeconfig
        command: aws eks update-kubeconfig --name $CLUSTER_NAME

    - run:
        name: login to dockerhub
        command: echo $DOCKER_HUB_PSW | base64 -d | docker login -u $DOCKER_HUB_USR --password-stdin

    - run:
        name: install skaffold
        command: |
          curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v0.32.0/skaffold-linux-amd64 && \
          chmod +x skaffold && \
          mv skaffold /usr/local/bin

    - run:
        name: skaffold run
        command: skaffold run --profile prd

workflows:
  version: 2
  workflow:
    jobs:
    - build

GitHubにPush

この状態でもろもろをGitHubにPushしてあげると…
CircleCI上でskaffold run --profile prdが実行され、もろもろの処理が走ります。

screencapture-circleci-gh-Kta-M-skaffold-example-10-2019-07-01-06_02_44.png

$ kubectl get svc
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP                               PORT(S)        AGE
service/frontend       LoadBalancer   10.100.61.11     xxxxxx.ap-northeast-1.elb.amazonaws.com   80:31673/TCP   8s
service/kubernetes     ClusterIP      10.100.0.1       <none>                                    443/TCP        23m
service/redis-master   ClusterIP      10.100.137.217   <none>                                    6379/TCP       7s
service/redis-slave    ClusterIP      10.100.217.57    <none>                                    6379/TCP       7s

ELBのドメインを確認してアクセスすると、guestbookアプリが動いているのが確認できると思います!

まとめ

  • 「わりとゴツいやつ」から一歩進んで、Kubernetesを使った開発の具体的なイメージが掴めたのであれば幸いです😊
  • ただ、我々はKubernetes沼に足を踏み入れたばかり
    • 今回紹介しきれなかった用語、エコシステムなどまだ膨大に…
  • 俺たちの真の戦いはこれからだ!
Kta-M
fusic
個性をかき集めて、驚きの角度から世の中をアップデートしつづける。
https://fusic.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした