Edited at

今度はあんまりゴツくない!?「わりとゴツい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沼に足を踏み入れたばかり


    • 今回紹介しきれなかった用語、エコシステムなどまだ膨大に…



  • 俺たちの真の戦いはこれからだ!