Data Technology Lab Guide¶
はじめに¶
目的¶
- DXを支える根幹技術(3rd Platform)とNetApp製品を組み合わせることによる価値を触りながら体験
- 特定のシナリオに沿った関連技術の組み合わせ検証
- Labを通じての技術者コミュニティの創出
Contents¶
Level 0: 環境の確認・基本操作¶
目的・ゴール: ラボを実施する環境の確認¶
本ラボではkubernetesクラスタへの接続確認と稼働確認を行うことが目的です。
ガイドの中では以下を確認しています。
- ラボを実施する環境の構成理解
- 環境への接続確認
- kubernetesの基本操作を確認
流れ¶
- ユーザIDの確認
- 環境へログイン
- 基本コマンド確認、k8s へアプリケーションデプロイ
kubernetes環境へのログイン¶
各自配布されている接続先情報にログイン出来るかを確認してください。
kubernetesにデプロイ¶
kubernetes基本操作¶
必要となるコマンドラインツールがインストールされていることを確認します。
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.6", GitCommit:"9f8ebd171479bec0ada837d7ee641dec2f8c6dd1", GitTreeState:"clean", BuildDate:"2018-03-21T15:21:50Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.6", GitCommit:"9f8ebd171479bec0ada837d7ee641dec2f8c6dd1", GitTreeState:"clean", BuildDate:"2018-03-21T15:13:31Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
次にクラスタを形成するノードを確認します。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 6d v1.9.6
node0 Ready <none> 6d v1.9.6
node1 Ready <none> 6d v1.9.6
node2 Ready <none> 6d v1.9.6
デプロイメント¶
kubernetesクラスタに作成したコンテナアプリケーションをデプロイするためには 「Deployment」を作成します。 kubectlを使用して、アプリケーションをデプロイします。
以下では kubectl run
を実行すると「Deployment」が作成されます。
$ kubectl run 任意のデプロイメント名 --image=nginx --port=80
deployment "nginxweb" created
デプロイが完了したら以下のコマンドで状況を確認します。
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginxweb 1 1 1 1 53s
デプロイしたアプリケーションのサービスを確認します。 まだこの状態ではデプロイしたアプリケーションのサービスは存在しない状況です。
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8s
外部向けに公開¶
外部向けにサービスを公開します。 公開後、再度サービスを確認します。
$ kubectl expose deployment/上記のデプロイメント名 --type="NodePort" --port 80
service "nginxweb" exposed
kubectl expose
コマンドで外部へ公開しました。
サービス一覧から公開されたポートを確認します。
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d
nginxweb NodePort 10.103.136.206 <none> 80:30606/TCP 1m
PORT 列を確認します。上の実行例でいうと「30606」ポートの部分を確認します。
--type="NodePort"
を指定すると各ノード上にアプリケーションにアクセスするポート(標準で30000–32767)を作成します。
ノードにアクセスしポッドが動いていれば、そのままアクセスします。
ノードにポッドがなければ適切なノード転送される仕組みを持っています。
そのためマスターノードにアクセスすればk8sが適切に転送するという動作をします。
ホストのIPを確認します。
$ ifconfig -a | grep 192.168.*
inet addr:192.168.10.10 Bcast:192.168.10.255 Mask:255.255.255.0
上記の情報を元にIPを生成してアクセスします。
- http://確認したIP:確認したポート番号/
アクセス時に以下の画面が表示されれば稼働確認完了です。

状態を確認します。
$ kubectl describe deployment nginxweb
Name: nginxweb
Namespace: default
CreationTimestamp: Tue, 20 Mar 2018 13:44:08 +0900
Labels: run=nginxweb
Annotations: deployment.kubernetes.io/revision=1
Selector: run=nginxweb
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: run=nginxweb
Containers:
nginxweb:
Image: nginx
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: nginxweb-78547ccd78 (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 15m deployment-controller Scaled up replica set nginxweb-78547ccd78 to 1
Replicas の項目で 1 available
となっていればデプロイメント成功です。
問題発生時のログの確認方法¶
デプロイに失敗するようであれば以下のコマンドで状態を確認します。
ポッドの状態を確認するコマンド
$ kubectl logs ポッド名
デプロイメントの状態を確認するコマンド
$ kubectl describe deployments デプロイメント名
他にも以下のようなコマンドで状態を確認することができます。 デプロイ時のYAMLファイル単位や、定義しているラベル単位でも情報を確認できます。
$ kubectl describe -f YAML定義ファイル
$ kubectl describe -l ラベル名
よく使うコマンドや問題発生時の確認方法については次のページにまとめました。 今後のラボでうまくいかない場合いはぜひ参考にしてください。
クリーンアップ¶
コマンドラインの操作は完了です。 今までデプロイしたアプリケーションを削除します。
$ kubectl delete deployments デプロイメント名
$ kubectl delete services サービス名
Level 1: アプリケーションをコンテナ化する¶
目的・ゴール: アプリケーションをコンテナ化する¶
今回はコンテナに適したアーキテクチャへ変更するまえの段階として、 オンプレミスで仮想マシンで動いているアプリケーションについてコンテナ化をしていきます。
コンテナ技術のDockerを使うことでクラウド、オンプレミス、PCなどどのような環境でもアプリケーションを稼働させることができます。
具体的にはコンテナイメージをpullし、実行します。 その結果、アプリケーションがコンテナとして起動します。
このレベルではこのあとのラボで使用するKubernetes上で稼働させるアプリケーションのコンテナイメージを作成するのがの目標です。
流れ¶
- Dockerfileを作成する。
- ビルドを行いDockerイメージを作成
- 作成したDockerイメージをDocker Registryに登録
- どこからでもpull可能に(デプロイが可能に)
コンテナ化の準備¶
本ラボでは以下のミドルウェアやスタックを使ったアプリケーションを想定しています。 基本的にはアプリケーションをコンテナ化する際にはDockerHubで作成済みのイメージを使用することで効率よくコンテナ化することができます。
Web/AP レイヤー
- nginx
- apache
- tomcat
Databaseレイヤー
- mySQL
- Postgress
- Oracle
- MongoDB
コンテナイメージの作成¶
このステップはアプリケーションを持ち込みの場合や複雑なスタックをコンテナ化する際に行うステップです。選択したアプリケーションによっては不要なステップになるのでやるべきかどうかを確認してください。
その場合、 アプリケーションのマニフェストファイルを作成してデプロイ からはじめてください。
想定するアプリケーションのコンテナイメージを作成します。
Dockerfile のリファレンス Dockerfile Reference ファイル
留意点としては以下の通りです。
アプリケーションの配置をDockerfile内に配置
基本となるコンテナイメージについてはDockerHubで探してベースイメージとする
静的な構成となっていないか(IPパスワードのべた書きなど)
- 環境変数で設定出来るよう設計する。のちほどk8sのSecretなどでパスワードを保存
冪等性はコンテナイメージ側で対応する。責任範囲を明確にしてイメージを作成
ステートフルなものについてはコンテナに適したものにする
- データ永続化については Level 2: ステートフルコンテナの実現 にて実施
ヒント
記述例を提示します。このままビルドしてもイメージは作成されませんのであくまで記述例としてみてください。 どうしても進まない場合は サンプル: Dockerfile記述例 をクリックしてください。
コンテナイメージのビルド¶
作成した Dockerfileをビルドしてイメージを作成します。
バージョニングを意識してコンテナイメージを作成します、コンテナイメージに明示的にバージョンを指定します。
$ docker build -t 生成するコンテナイメージ名:タグ名 Dockerファイルのパス
Dockerイメージの生成方法は複数の手法があります。 例えば、普通のOSイメージを起動して、ログインしパッケージなどのインストールを行っていく手法があります。 メリットとしてはオペレーションで作成したものをイメージとして登録できるため、Dockerfileを作成しなくても良いといメリットがある一方で、 コンテナイメージの作成方法が不透明となる可能性もあります。
イメージレポジトリに登録¶
今回はイメージレポジトリにDockerHubを使用します。
DockerHub へログイン¶
DockerHubにアカウントがあることが前提です。
$ docker login
ユーザ名、パスワードを入力
$ docker image push アカウント名/コンテナイメージ名:タグ名
アプリケーションのマニフェストファイルを作成してデプロイ¶
Level 0: 環境の確認・基本操作 ではコマンドラインで作成してきましたがYAMLファイルで1サービスをまとめてデプロイ出来るようにします。
ファイルのセクション構成としては以下の通りです。
- Service
- PersistentVolumeClaim
- Deployment
サンプルファイルを準備しましたのでそれぞれの項目の意味を考え作成してみましょう。
(https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/ を参考としています。)
apiVersion: v1
kind: Service
metadata:
name: サービス名
labels:
app: 任意のラベル名
spec:
ports:
- port: ポート番号
selector:
app: アプリケーション名
tier: ティア名
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: デプロイメント名
labels:
app: アプリケーション名
spec:
selector:
matchLabels:
app: アプリケーション名
tier: ティア名
strategy:
type: Recreate
template:
metadata:
labels:
app: アプリケーション名
tier: ティア名
spec:
containers:
- image: イメージ名:タグ
name: アプリケーション名
env:
- name: PASSWORD
valueFrom:
secretKeyRef:
name: app-pass
key: password
ports:
- containerPort: ポート番号
name: アプリケーション名
アプリケーションの稼働確認¶
デプロイしたアプリケーションにアクセスし正常稼働しているか確認します。
アクセスするIPについてはサービスを取得して確認します。
$ kubectl get svc
結果として以下のような出力が得られます。
今回はServiceのtypeをNodePortで指定しているため、PORT(S)の」:」で区切られた右側のポート(以下の例だと32048)にアクセスしてみましょう。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d
wordpress NodePort 10.98.247.58 <none> 80:32048/TCP 2h
wordpress-mysql ClusterIP None <none> 3306/TCP 2h
注釈
kubectl引数の省略系について
今回はServiceの確認をする際に svc
という省略形でコマンドを実行しました。
他のオブジェクトも同様に省略形があります。コマンド入力を省力化したい場合は省略形も使ってみましょう。
kubectl --help
や kubectl XX --help
コマンドで確認できます。
まとめ¶
kubectlやYAMLで記載するマニフェストファイルを使ってk8sへのデプロイが体感できたかと思います。 実運用になるとこのYAMLをたくさん書くことは負荷になることもあるかもしれません.
その解決のためにパッケージマネージャーHelm 等を使ってデプロイすることが多いかと思います。 このラボでは仕組みを理解していただき、応用出来ることを目的としています。
ここまでで Level1 は終了です。
Level 2: ステートフルコンテナの実現¶
目的・ゴール: アプリケーションのデータ永続化を実現¶
アプリケーションは永続化領域がないとデータの保存ができません。 KubernetesではStatic provisioningとDynamic provisioningの2つの永続化の手法があります。
このレベルではDynamic provisioningを実現するためDynamic provisonerであるTridentをインストールし、 マニフェストファイルを作成しデータの永続化をすることが目標です。
流れ¶
Dynamic storage provisioningを実現(Tridentのインストール)
StorageClassの作成
PVCをkubernetesマニフェストファイルに追加
- 作成したStorageClassを使用する
- PVCをkubernetesにリクエストした時点で動的にストレージがプロビジョニングされる
アプリケーションを稼働させて永続化ができていることを確認
コンテナでの永続データのカテゴライズ¶
コンテナ化されたアプリケーション、環境での永続データは 以下のように分類して考え必要な物をリストアップしました。
- データベースのデータファイル、ログファイル
- 各サーバのログファイル
- 設定ファイル
- 共有ファイル
Dynamic provisioning¶
ステートフルコンテナを実現する上でストレージは重要なコンポーネントになります。
Dynamic volume provisiong はオンデマンドにストレージをプロビジョニングするためのものです。
Static provisioning、Dynamic provisioning それぞれを比較します。
Static provisioningの場合、クラスタの管理者がストレージをプロビジョニングして、PersitentVolumeオブジェクトを作成しkubernetesに公開する必要があります。
Dynamic provisioningの場合、Static provisioningで手動で行っていたステップを自動化し、管理者がおこなっていたストレージの事前のプロビジョニング作業をなくすことができます。
StorageClassオブジェクトで指定したプロビジョナを使用し、動的にストレージリソースをプロビジョニングすることができます。
StorageClassには様々なパラメータを指定することができアプリケーションに適したストレージカタログ、プロファイルを作成することができ、物理的なストレージを抽象化するレイヤとなります。
ネットアップはDynamic provisioningを実現するためのNetApp Tridentというprovisionerを提供しています。
このレベルではTridentでDynamic provisioningを行い、アプリケーションのデータ永続化を実現します。
NetApp Tridentのインストール¶
Dynamic storage provisioningを実現するためNetApp Tridentを導入します。 TridentはPodとしてデプロイされ通常のアプリケーションと同様に稼働します。
Tridentインストール事前準備¶
Trident のインストールでk8sクラスタの管理者権限が必要になります。
$ kubectl auth can-i '*' '*' --all-namespaces
バックエンドに登録するマネジメントIPにk8sクラスタのコンテナから疎通が取れるかを確認します。
$ kubectl run -i --tty ping --image=busybox --restart=Never --rm -- ping [ipアドレス]
Tridentインストール¶
バイナリをダウンロードしてインストールします。
バックエンドストレージのための setup/backend.json
を編集します。以下はサンプルとなります。
$ wget https://github.com/NetApp/trident/releases/download/v18.01.0/trident-installer-18.01.0.tar.gz
$ tar xzf trident*.tar.gz && cd trident-installer
$ cp sample-input/backend-ontap-nas.json setup/backend.json
パラメータ名 | 説明 | 設定内容 |
---|---|---|
managementLIF | ONTAPのクラスタ管理LIFまたはSVM管理LIFを設定 | 192.168.XX.200 |
dataLIF | データ通信LIF | 192.168.XX.200 |
svm | tridentから使用するSVM | svmXX |
username/password | クラスタ管理者またはSVM管理者のクレデンシャル | 今回SVM管理者を設定: vsadmin/netapp123 |
「XX」はユーザ環境番号になります。
編集後は以下の通りとなります。 疎通が取れないIPを設定するとtridentデプロイが失敗します。
$ cat setup/backend.json
{
"version": 1,
"storageDriverName": "ontap-nas",
"managementLIF": "192.168.XX.200",
"dataLIF": "192.168.XX.200",
"svm": "svmXX",
"username": "vsadmin",
"password": "netapp123"
}
$ ./install_trident.sh -n trident
インストールの進捗を確認します。
$ kubectl get pod -n trident -aw
NAME READY STATUS RESTARTS AGE
trident-ephemeral 1/1 Running 0 58s
``-aw``オプションをつけることでPodの動きに変化があれば自動的にリロードしてくれます。
上記の状態で止まってしまう場合は、 trident-installer/
配下に tridentctl
というtridentのコマンドラインユーティリティが同梱されています。
このツールを使って状況を確認します。
tridentctlはパスの通った場所に配置します。
$ sudo cp tridentctl /usr/local/bin
以下のようにtridentに関するログをまとめて確認することが出来るようになります。
$ tridentctl -n trident logs
time="2018-02-15T03:32:35Z" level=error msg="API invocation failed. Post https://10.0.1.146/servlets/netapp.servlets.admin.XMLrequest_filer: dial tcp 10.0.1.146:443: getsockopt: connection timed out"
time="2018-02-15T03:32:35Z" level=error msg="Problem initializing storage driver: 'ontap-nas' error: Error initializing ontap-nas driver. Could not determine Data ONTAP API version. Could not read ONTAPI version. Post https://10.0.1.146/servlets/netapp.servlets.admin.XMLrequest_filer: dial tcp 10.0.1.146:443: getsockopt: connection timed out" backend= handler=AddBackend
time="2018-02-15T03:32:35Z" level=info msg="API server REST call." duration=2m10.64501326s method=POST route=AddBackend uri=/trident/v1/backend
Tridentへバックエンドストレージの登録¶
インストールが完了したことを確認します。
$ tridentctl -n trident version
+----------------+----------------+
| SERVER VERSION | CLIENT VERSION |
+----------------+----------------+
| 18.01.0 | 18.01.0 |
+----------------+----------------+
バージョンが表示されていればインストール成功です。
作成した setup/backend.json
を指定し作成します。
$ tridentctl -n trident create backend -f setup/backend.json
+-------------------------+----------------+--------+---------+
| NAME | STORAGE DRIVER | ONLINE | VOLUMES |
+-------------------------+----------------+--------+---------+
| ontapnas_192.168.10.200 | ontap-nas | true | 0 |
+-------------------------+----------------+--------+---------+
(Troubleshooting) Tridentをアンインストールする¶
trident-installer
にアンインストール用のシェルスクリプトが入っています。
以下の用に -a
オプションを付与して実行すると生成した管理用のetcdのデータなどすべてを削除した上でアンインストールします。
$ ./uninstall_trident.sh -n trident -a
インストール時にうまくいかずに試行錯誤した際には一度クリーンアップすることをおすすめします。
例えば、v18.01のTridentでは以下の項目をStorageClassを作成するときに設定できます。
- 性能に関する属性: メディアのタイプ、プロビジョニングのタイプ(シン・シック)、IOPS
- データ保護・管理に関する属性:スナップショット、クローニング、暗号化の有効・向こう
- バックエンドのストレージプラットフォーム
全てのパラメータ設定については以下のURLに記載があります。
StorageClassの定義¶
StorageClassを定義して、ストレージのサービスカタログを作りましょう。
- DB 用の高速領域: SSD を使ったストレージサービス
- Web コンテンツ用のリポジトリ: HDDを使ったストレージサービス
ストレージ構成は以下の通りです。 今回、意識する必要があるところは異なるメディアタイプ(HDDとSSD)のアグリゲートを保有しているところです。
ONTAP 9.3
各SVMにHDD, SSDのアグリゲートを割り当て済み
- aggr1_01:SSDのアグリゲート
- aggr2_01:HDDのアグリゲート
StorageClassの作成方法のサンプルは以下の通りです。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ontap-gold
provisioner: netapp.io/trident
parameters:
backendType: "ontap-nas"
media: "ssd"
provisioningType: "thin"
snapshots: "true"
ストレージクラスを作成します。
$ kubectl create -f StorageClassFastest.yml
storageclass "ontap-gold" created
$ kubectl get sc
NAME PROVISIONER AGE
ontap-gold netapp.io/trident 10s
Persistent Volume Claimの作成¶
アプリケーションで必要とされる永続化領域の定義をします。 PVCを作成時に独自の機能を有効化することができます。
reclaimPolicy
によってポッドがなくなった際のデータの保管ポリシーの設定ができます。
他にもデータ保護、SnapShotの取得ポリシーなどを設定できます。
一覧については以下のURLに記載があります。
デプロイ用のマニフェストファイルににPVCを追加¶
Level1で作成したマニフェストファイルにPVCの項目を追加し、ダイナミックプロビジョニングで永続化出来るアプリケーションを定義します。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sample-pv-claim
labels:
app: アプリケーション名
annotations:
trident.netapp.io/reclaimPolicy: "Retain"
trident.netapp.io/exportPolicy: "default"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: ontap-gold
アプリケーションの停止¶
永続化されていることを確認するため、一度アプリケーションを停止します。 可能であればアプリケーションのバージョンアップを行ってみましょう。
Deploymentで必ず1つのポッドは起動するような設定になっているため、 簡単に実施するためにはポッドを削除する手段がとれます。 DeploymentによってPodの起動数は管理されるため新たにポッドが起動します。
再デプロイメント¶
再起動したPodに対してボリュームがマウントされていることを確認することも可能です。 容易に行える操作としてはDeployment配下にあるPodを削除し、Deploymentによって起動し直させるといったやり方です。
- アプリケーションであれば再度ログインし、保存したデータを確認します。
- 通常運用のリリースに想定するオペレーションをして、外部ストレージにデータ永続化されていることを確認します。
動的にボリュームが作成されていることを確認します。
$ ssh vsadmin@192.168.20.20 vol show
Password:
Vserver Volume Aggregate State Type Size Available Used%
--------- ------------ ------------ ---------- ---- ---------- ---------- -----
tridentsvm root aggr1 online RW 1GB 972.2MB 5%
tridentsvm trident_trident aggr1 online RW 1.86GB 1.77GB 5%
tridentsvm trident_trident_basic_f4048 aggr1 online RW 1GB 972.4MB 5%
3 entries were displayed.
Tridentの特徴的な機能: Fast Cloning¶
Tridentには特徴的な機能であるクローニングの機能が存在します。
**巨大なボリュームでも容量消費せずに超高速にデータをコピーする**クローニングテクノロジーがkubernetesから使用可能となります。
ユーザーが既存のボリュームを複製することによって新しいボリュームをプロビジョニングできる機能を提供しています。
PVCアノテーションである、trident.netapp.io/cloneFromPVC
を介してクローン機能を利用できます。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: basicclone
annotations:
trident.netapp.io/cloneFromPVC: database
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: ontap-gold
クローニング技術によって実現可能なこと¶
クローニング技術はシンプルですが非常に多く用途で使用することができます。 例としてあげられるのが以下の通りのことです。
- プレビルド環境の高速展開
- 本番環境に影響せずに大規模な並列テスト
- 運用時のデータリストアの高速化、瞬時に論理障害を戻す
まとめ¶
アプリケーションに対して動的に永続化領域をプロビジョニングしデータの永続化を実現しました。
今回はStorageClassの作成からアプリケーションにPersistentVolumeを割り当てるところまでを一連の流れで実現しました。
本来であればそれぞれで役割がことなるため以下のような分担になるかと思います。
- StorageClassの作成: インフラ・kubernetesクラスタの管理者
- PersistentVolumeClaimの作成: 利用者
今後障害時の動作が気になると思いますが、 Level 4: 運用編 での検討事項とします。
ここまでで Level2 は終了です。
Level 3: CI/CDパイプラインを構築¶
目的・ゴール: コンテナ化したアプリケーションのCICDを実現する¶
アプリケーションをコンテナ化したら、常にリリース可能な状態、自動でデプロイメントを出来る仕組みをつくるのが迅速な開発をするために必要になります。
そのためのCI/CDパイプラインを作成するのがこのレベルの目標です。

本ラボでは Level1, Level2 で行ったオペレーションをベースにCI/CDパイプラインを構築します。
Gitにソースがコミットされたら自動でテスト・ビルドを実現するためのツール(Jenkins)をkubernetes上へデプロイ、及び外部公開をします。 そして、Jenkinsがデプロイできたら実際にアプリケーションの変更を行い自動でデプロイするところまでを目指します。
流れ¶
- Jenkins をインストールする
- Jenkins 内部でジョブを定義する。
- あるアクションをトリガーにビルド、テストを自動実行する。
- 自動でk8sクラスタにデプロイメントできるようにする。
CI/CDパイプラインの定義¶
このラボでのCI/CDパイプラインの定義は以下を想定しています。
- テスト実行
- アプリケーションビルド
- コンテナイメージのビルド
- レジストリへコンテナイメージのpush
- k8sへアプリケーションデプロイ
Gitは共有で準備しています。
ここではJenkinsをkubernetes上にデプロイしてみましょう。 Git自体も併せてデプロイしてみたいということであればGitLabをデプロイすることをおすすめします。 GitLabを使えばコンテナのCI/CDパイプライン、構成管理、イメージレジストリを兼ねて使用することができます。
Jenkinsのデプロイ方法について¶
CI/CDパイプラインを実現するためのツールとしてJenkinsが非常に有名であることは周知の事実です。 このラボではJenkinsを使用しCI/CDを実現します。
まずは、各自Jenkinsをデプロイします。
方法としては3つ存在します。
- Helm Chartでデプロイする方法 (手軽にインストールしたい人向け)
- Level1,2と同じようにyamlファイルを作成し、デプロイする方法(仕組みをより深く知りたい人向け)
- Kubernetes用にCI/CDを提供するJenkins Xをデプロイする方法(新しい物を使いたい人向け)
今回は最初のHelmでデプロイするバージョンを記載しました。 好みのもの、挑戦したい内容に沿って選択してください。
オリジナルでyamlファイルを作成する場合は以下のサイトが参考になります。
Helmを使ってJenkinsをデプロイ¶
Helmの初期化¶
Helmを使用する事前の設定をします。 Helmの初期化、RBACの設定を実施します。
$ helm init
$ kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
Helmチャートのインストール・Jenkinsのカスタマイズ¶
今回はJenkinsを導入するにあたり環境に併せてカスタマイズを行います。 Helmは以下のURLに様々なものが公開されています。パラメータを与えることである程度カスタマイズし使用することができます。 Helm chartと同等のディレクトリにvalues.yamlというファイルが存在し、これを環境に併せて変更することでカスタマイズしデプロイできます。
今回のJenkinsのデプロイでは2つの公開方法が選択できます。
1つ目が今までのレベルと同様に Service
の type
を NodePort
として公開する方法です。これは今まで通りの疎通確認が可能です。
2つ目が Ingress
を使った公開です。IngressをJenkinsのHelmチャートを使ってデプロイするためには「Master.Ingress.Annotations」、「Master.ServiceType」を変更しデプロイします。
また、このvalues.yamlでは永続化ストレージが定義されていないため、Level2で作成したStorageClassを使用し動的にプロビジョニングをするように変更しましょう。
簡易的にデプロイをためしてみたい方は1つ目の NodePort
を使ったやり方を実施、新しい概念であるIngressを使った方法を実施したい方は2つ目を選択しましょう。
どちらの方法の場合も、以下のvalues.yamlをカスタマイズしてデプロイします。
# Default values for jenkins.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
# name: value
## Overrides for generated resource names
# See templates/_helpers.tpl
# nameOverride:
# fullnameOverride:
Master:
Name: jenkins-master
Image: "jenkins/jenkins"
ImageTag: "lts"
ImagePullPolicy: "Always"
# ImagePullSecret: jenkins
Component: "jenkins-master"
UseSecurity: true
AdminUser: admin
# AdminPassword: <defaults to random>
Cpu: "200m"
Memory: "256Mi"
# Environment variables that get added to the init container (useful for e.g. http_proxy)
# InitContainerEnv:
# - name: http_proxy
# value: "http://192.168.64.1:3128"
# ContainerEnv:
# - name: http_proxy
# value: "http://192.168.64.1:3128"
# Set min/max heap here if needed with:
# JavaOpts: "-Xms512m -Xmx512m"
# JenkinsOpts: ""
# JenkinsUriPrefix: "/jenkins"
# Set RunAsUser to 1000 to let Jenkins run as non-root user 'jenkins' which exists in 'jenkins/jenkins' docker image.
# When setting RunAsUser to a different value than 0 also set FsGroup to the same value:
# RunAsUser: <defaults to 0>
# FsGroup: <will be omitted in deployment if RunAsUser is 0>
ServicePort: 8080
# For minikube, set this to NodePort, elsewhere use LoadBalancer
# Use ClusterIP if your setup includes ingress controller
ServiceType: LoadBalancer
# Master Service annotations
ServiceAnnotations: {}
# service.beta.kubernetes.io/aws-load-balancer-backend-protocol: https
# Used to create Ingress record (should used with ServiceType: ClusterIP)
# HostName: jenkins.cluster.local
# NodePort: <to set explicitly, choose port between 30000-32767
ContainerPort: 8080
# Enable Kubernetes Liveness and Readiness Probes
HealthProbes: true
HealthProbesTimeout: 60
SlaveListenerPort: 50000
# Kubernetes service type for the JNLP slave service
# SETTING THIS TO "LoadBalancer" IS A HUGE SECURITY RISK: https://github.com/kubernetes/charts/issues/1341
SlaveListenerServiceType: ClusterIP
SlaveListenerServiceAnnotations: {}
LoadBalancerSourceRanges:
- 0.0.0.0/0
# Optionally assign a known public LB IP
# LoadBalancerIP: 1.2.3.4
# Optionally configure a JMX port
# requires additional JavaOpts, ie
# JavaOpts: >
# -Dcom.sun.management.jmxremote.port=4000
# -Dcom.sun.management.jmxremote.authenticate=false
# -Dcom.sun.management.jmxremote.ssl=false
# JMXPort: 4000
# List of plugins to be install during Jenkins master start
InstallPlugins:
- kubernetes:1.1
- workflow-aggregator:2.5
- workflow-job:2.15
- credentials-binding:1.13
- git:3.6.4
# Used to approve a list of groovy functions in pipelines used the script-security plugin. Can be viewed under /scriptApproval
# ScriptApproval:
# - "method groovy.json.JsonSlurperClassic parseText java.lang.String"
# - "new groovy.json.JsonSlurperClassic"
# List of groovy init scripts to be executed during Jenkins master start
InitScripts:
# - |
# print 'adding global pipeline libraries, register properties, bootstrap jobs...'
# Kubernetes secret that contains a 'credentials.xml' for Jenkins
# CredentialsXmlSecret: jenkins-credentials
# Kubernetes secret that contains files to be put in the Jenkins 'secrets' directory,
# useful to manage encryption keys used for credentials.xml for instance (such as
# master.key and hudson.util.Secret)
# SecretsFilesSecret: jenkins-secrets
# Jenkins XML job configs to provision
# Jobs: |-
# test: |-
# <<xml here>>
CustomConfigMap: false
# Node labels and tolerations for pod assignment
# ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
# ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature
NodeSelector: {}
Tolerations: {}
Ingress:
Annotations:
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
TLS:
# - secretName: jenkins.cluster.local
# hosts:
# - jenkins.cluster.local
Agent:
Enabled: true
Image: jenkins/jnlp-slave
ImageTag: 3.10-1
# ImagePullSecret: jenkins
Component: "jenkins-slave"
Privileged: false
Cpu: "200m"
Memory: "256Mi"
# You may want to change this to true while testing a new image
AlwaysPullImage: false
# You can define the volumes that you want to mount for this container
# Allowed types are: ConfigMap, EmptyDir, HostPath, Nfs, Pod, Secret
# Configure the attributes as they appear in the corresponding Java class for that type
# https://github.com/jenkinsci/kubernetes-plugin/tree/master/src/main/java/org/csanchez/jenkins/plugins/kubernetes/volumes
volumes:
# - type: Secret
# secretName: mysecret
# mountPath: /var/myapp/mysecret
NodeSelector: {}
# Key Value selectors. Ex:
# jenkins-agent: v1
Persistence:
Enabled: true
## A manually managed Persistent Volume and Claim
## Requires Persistence.Enabled: true
## If defined, PVC must be created manually before volume will be bound
# ExistingClaim:
## jenkins data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# StorageClass: "-"
Annotations: {}
AccessMode: ReadWriteOnce
Size: 8Gi
volumes:
# - name: nothing
# emptyDir: {}
mounts:
# - mountPath: /var/nothing
# name: nothing
# readOnly: true
NetworkPolicy:
# Enable creation of NetworkPolicy resources.
Enabled: false
# For Kubernetes v1.4, v1.5 and v1.6, use 'extensions/v1beta1'
# For Kubernetes v1.7, use 'networking.k8s.io/v1'
ApiVersion: extensions/v1beta1
## Install Default RBAC roles and bindings
rbac:
install: false
serviceAccountName: default
# RBAC api version (currently either v1beta1 or v1alpha1)
apiVersion: v1beta1
# Cluster role reference
roleRef: cluster-admin
実行イメージとしては以下の通りです。
$ helm --namespace jenkins --name jenkins -f ./jenkins-values.yaml install stable/jenkins --debug
LAST DEPLOYED: Tue Apr 24 12:47:12 2018
NAMESPACE: jenkins
STATUS: DEPLOYED
RESOURCES:
==> v1/Secret
NAME TYPE DATA AGE
jenkins Opaque 2 8m
==> v1/ConfigMap
NAME DATA AGE
jenkins 3 8m
jenkins-tests 1 8m
==> v1/PersistentVolumeClaim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
jenkins Bound jenkins-jenkins-2c478 8Gi RWO ontap-gold 8m
==> v1/ServiceAccount
NAME SECRETS AGE
jenkins 1 8m
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-agent ClusterIP 10.98.21.68 <none> 50000/TCP 8m
jenkins NodePort 10.96.24.25 <none> 8080:31050/TCP 8m
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
jenkins 1 1 1 1 8m
==> v1beta1/Ingress
NAME HOSTS ADDRESS PORTS AGE
jenkins jenkins.user21.web.service.consul 80 8m
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
jenkins-578686f98d-6pbx9 1/1 Running 0 8m
==> v1beta1/ClusterRoleBinding
NAME AGE
jenkins-role-binding 8m
NOTES:
1. Get your 'admin' user password by running:
printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
2. Visit http://jenkins.user21.web.service.consul
3. Login with the password from step 1 and the username: admin
For more information on running Jenkins on Kubernetes, visit:
https://cloud.google.com/solutions/jenkins-on-container-engine
Configure the Kubernetes plugin in Jenkins to use the following Service Account name jenkins using the following steps:
Create a Jenkins credential of type Kubernetes service account with service account name jenkins
Under configure Jenkins -- Update the credentials config in the cloud section to use the service account credential you created in the step above.
「NOTES」欄に記載の通りadminパスワードを取得します。
$ printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
sShJg2gig9
以上で、Jenkinsのデプロイが完了しました。
Helmが生成するマニフェストファイル¶
Helmを使いvalues.yamlを定義するとどのようなマニフェストファイルが生成されるかが予測しづらいこともあります。
その場合には --dry-run
と --debug
を付与することでデプロイメントされるYAMLファイルが出力されます。
helm –namespace jenkins –name jenkins -f ./values.yaml install stable/jenkins –dry-run –debug
インストールが上手くいかない場合は?¶
values.yamlを試行錯誤しながら設定していくことになると思います。 一度デプロイメントしたHelmチャートは以下のコマンドで削除することができます。
$ helm del --purge チャート名
Helm以外でJenkinsをデプロイした場合¶
本セクションに記載してあることはオプションです。
必要に応じて実施してください。
外部にアプリケーションを公開する方法として Ingress
があります。
Helmを使ってJenkinsをインストールした場合は自動でIngressが作成されます。
それ以外の手法を取った場合は、kubernetesクラスタ外のネットワークからアクセスできるようにIngressを作成してみましょう。
Helm chart を使ってインストールした場合は自動でIngressが導入されています。
そのため、以下の手順はHelmで実施した人は不要です。
Ingressの導入についてはこちらに Ingressを導入する まとめました。
ServiceをDNSへ登録する¶
HelmでデプロイしたJenkinsにはIngress経由でアクセスします。 そのためホスト名を使用してアクセスします。
注釈
なぜそのような仕組みになっているかを知りたい方はJenkinsのHelmチャートをご確認ください。 https://github.com/kubernetes/charts/tree/master/stable/jenkins
今回は名前解決にConsulを使います。
登録用JSONは以下の通りです、TagsとNameでdnsに問い合わせる名前が決まります。
今回はドメインを service.consul
を使用します。
このラボでは命名規則を定義します。
- ID, Tags: アプリケーション識別子.環境番号
- Name: web固定
- Address: 各環境のマスタのIP
アプリケーションにアクセスする際に jenkins.user10.web.service.consul
というFQDNでアクセスしたい場合は以下のjsonファイルを作成します。
ファイル名はwebservice.jsonとします。ポート番号はアプリケーションで使用しているものに変更してください。
{
"ID": "jenkins.user10",
"Name": "web",
"Tags": [ "jenkins.user10" ],
"Address": "192.168.XX.10",
"Port": 80
}
ファイルを作成したら以下のコマンドで登録します。
$ curl -i -s --request PUT --data @webservice.json http://infra1:8500/v1/agent/service/register
HTTP/1.1 200 OK
Date: Wed, 11 Apr 2018 05:31:37 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8
登録が完了したら名前解決ができるか確認します。
$ nslookup jenkins.user10.web.service.consul
Jenkinsの設定をする¶
Gitリポジトリに変更があったら自動でテストを実行するジョブを定義します。 このテストは任意で作成してください。
ここでやりたいことは該当リポジトリにコミットがあり、リリースタグが付与された場合に自動でビルド・デプロイをする流れを作成することです。 そのためにはまずJenkinsでGitリポジトリに操作があった場合の動作を定義します。
定義出来る動作としては以下の単位が考えられます。 細かく設定することも可能です。運用に合わせた単位で設定します。
- pull request 単位
- release tag 単位
- 定期実行
前述した以下の項目を盛り込みCI/CDパイプラインを作成しましょう。 以下のようなタスクを組み込んだパイプラインを作成します。シンプルなパイプラインからはじめ、必要に応じてステージを追加していきましょう。
- テスト実行
- アプリケーションビルド
- コンテナイメージのビルド
- レジストリへコンテナイメージのpush
- アプリケーションデプロイ
上記のようなパイプラインを作成にはJenkins pipeline機能が活用できます。
アプリケーションの変更を検知してデプロイメント可能にする¶
CI/CDのパイプラインを作成したら実際にアプリケーションの変更をトリガーに(ソースコードの変更、Gitリポジトリへのpush等)k8sへアプリケーションをデプロイします。
ポリシーとして大きく2つに別れます、参考までに以下に記載いたします。
- デプロイ可能な状態までにし、最後のデプロイメントは人が実施する(クリックするだけ)
- デプロイメントまでを完全自動化する
実際にkubernetes環境へのデプロイができたかの確認とアプリケーションが稼働しているかを確認します。
Helm ChartでCI/CD¶
個別のアプリケーションデプロイメントからHelm Chartを使ったデプロイメントに変更します。
作成したコンテナをHelm Chartを使ってデプロイするようにします。
Helm Chartの開発ガイドは以下のURLを確認ください。
デプロイメントのさらなる進化¶
CI/CDプロセスを成熟させていくと常にリリース可能な状態となっていきます。 そのような状態になると本番環境へのデプロイを迅速にし、ダウンタイムを最小化するための方法が必要になってきます。 元々存在するプラクティスや考え方となりますがコンテナ技術、kubernetesのスケジューラー機能を使うことで今までの環境とくらべて実現がしやすくなっています。
Blue/Greenデプロイメント, Canary リリースというキーワードで紹介したいと思います。
Blue/Greenデプロイメント¶
従来のやり方では1つの環境にデプロイし何かあれば戻すという方法をほとんどのケースで採用していたかと思いますが、さらなる進化として常に戻せる環境を準備し迅速にロールバック 新バージョン、旧バージョンをデプロイしたままルータで切り替えるようになります。
様々な企業で行き着いている運用でもあるかと思いますが、2010年にBlueGreenデプロイメントという名称で説明しています。
実現方法、切り替えのタイミングなどあり、BlueGreenの実装の決定的なものはなく、1つのプラクティスとして存在しています。
2つの環境を準備し、どこかのタイミングで切り替えを行うためDBのマイグレーションの方法などを検討する必要はでてきます。
Canary¶
Canary リリースは BlueGreen デプロイメントと類似したデプロイメントになります。 Blue/Green デプロイメントはすぐに古いバージョンにもどせるように仕組みを整えたものですが、Canaryリリースは新しいバージョン、旧バージョンにアクセスする比率を決めてデプロイするプラクティスです。
こちらは2つの環境ではなく、1環境に複数バージョンのアプリケーションが存在することになります。そのためDBのデータをどのように取り扱うかは検討が必要となります。
まとめ¶
このラボではコンテナ化したアプリケーションのCI/CDパイプラインの構築に挑戦しました。 CI/CDパイプラインを作成するためのJenkins/GitLabをインストールするために必要なHelmの使い方、アプリケーションを外部に公開するためのkubernetesオブジェクトのIngressも併せて使えるようになりました。
ここまでで Level3 は終了です。
Level 4: 運用編¶
目的・ゴール: ラボを実施する環境の確認¶
本番運用になった場合に必要となるアプリケーションの可用性、インフラの可用性、非機能要件の実現について検討します。
Level3まででアプリケーションを迅速にリリースする仕組みを作成しました。ここからはマスタのHA化やバックアップをどうするかを検討します。
流れ¶
本レベルでは運用時に課題となり、解決が必要となる項目についてリストしました。 現在の環境に対して変更をして見てください位。ここでは実際に手をうごかしてもらってもいいですし、 チーム内でディスカッションの材料にしてください。
アプリケーションの可用性を向上させる¶
アプリケーションの可用性を挙げるためWorkload APIを使用する¶
すでに Deployment
で使われているかもしれませんが、replica数などを定義できます。一般的なアプリケーションデプロイに使用します。
各ノードでコンテナを稼働させる DaemonSet
があります。ログ収集用のデーモンやメトリクス収集などのユースケースがあります。
レプリカ生成時の順序制御、各ポッドにPVを割り当てることができる StatefulSet
があります。主にクラスタ、分散環境におけるユースケースで使用するものです。
kubernetes上のオブジェクト名は以下の通りです。
- ReplicaSet
- DaemonSet
- StatefulSet
ローリングアップデート¶
Deployment
の ``Pod template``部分に変更があった場合に自動でアップデートできます。
$ kubectl set image deployment/DEPLOYMENT CONTAINER=IMAGE_NAME:TAG
``–record``オプションをつけるとアノテーションが付与されます。
参考: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
リリース後に問題発生、アプリケーションを戻す¶
アプリケーションは Deployment
でリビジョン管理しています。
rollout history
でリビジョンを確認できます。
$ kubectl rollout history deployment/デプロイメント名
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 <none>
2 <none>
各リビジョンの詳細については --revision=N
を付与することで詳細を確認できます。
$ kubectl rollout history deployment/nginx-deployment --revision=2
deployments "nginx-deployment" with revision #2
Pod Template:
Labels: app=nginx
pod-template-hash=1520898311
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
アプリケーションは Deployment
でリビジョン管理しており、ロールバック機能も提供しています。
rollout undo
で直前のリビジョンに戻ります。``–to-revision``を指定することで任意のリビジョンに戻すことも可能です。
$ kubectl rollout undo deployment/nginx-deployment [--to-revision=N]
保存されるリビジョンは revisionHistoryLimit
で定義できるため、運用に合わせた数にしましょう。
Helmを使った場合にも同様のことが実現可能です。
アプリケーション負荷に応じたスケールアウト・イン¶
Horizontal Pod Autoscaler
を使用してアプリケーションの負荷に応じてスケールアウトすることができます。
事前定義としてアプリケーションの負荷情報をheapsterで収集しておく必要があります。 以下の例はすべてのポッドのCPU使用率の平均が50%を超えた場合にレプリカを最大10まで増やす動作をします。
$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
上記の例では、CPU使用率をメトリクスとしていますが複数のメトリクスをしようしたり、カスタマイズすることも可能です。
参考: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
インフラの可用性を向上させる¶
k8s Master の冗長化¶
API受付をするマスタ系のノードやetcdやkubernetesサービスの高可用性も担保しましょう。
また、障害設計をどの単位(DC単位、リージョン単位)で行うかも検討をしましょう。
ログの確認、デバッグ方法¶
標準のkubectlだとログがおいづらいときがあるため以下のツールの検討をします。
- kubernetesホストの/var/log/containerにログは保管。(systemd系の場合)
- sternなどのログ管理ツールを活用する
- fluetdを使いログを集約する。
コンテナクラスタの監視¶
監視する対象として、メトリクス監視、サービス呼び出し、サービスメッシュなど分散環境になったことで従来型のアーキテクチャとは違った監視をする必要があります。 簡単にスケールアウトできる=監視対象が動的というような考え方をします。
また、分散環境では1つのアプリケーションでも複数のサービス呼び出しがおこなわれるため、どのようなサービス呼び出しが行われているかも確認できる必要があります。
- (heapster|Prometheus) + Grafana + InfluxDB を使いコンテナクラスタの監視。
- 分散環境に於けるサービスの呼び出しを可視化 Traces = Zipkin
- ServiceGraph Graphbiz & Prometeus
- ServiceMesh
セキュリティアップグレード¶
例えば、脆弱性があった場合の対処方法はどうすればよいか。
- ノードごとにバージョンアップするため、ある程度の余力を見込んだ設計とする。
- kubectl drain を使いノードで動いているPodを別ノードで起動、対象ノードをアップデートし、ポッドを戻す。
DRをどうするか?¶
アプリケーションのポータビリティはコンテナで実現。 別クラスタで作成されたPVはそのままは参照できないので以下の方法を検討する。
- Cluster federation
- CSI (Container Storage Interface)の既存ボリュームのインポートに対応をまつ
- Heptio ark: https://github.com/heptio/ark + SnapMirror
このチャプターはドラフト段階です。
Level 5: Microservice化¶
目的・ゴール: Microserviceを支えるインフラの技術・テクノロジースタックを活用¶
Level4までで既存のアプリケーションをコンテナ化して本番運用可能かつ迅速にリリースできる仕組みを作りました。 このレベルではアプリケーションをコンポーネント単位に分割していった際に必要となるインフラの仕組みを適用します。
流れ¶
- Microservice化していくにあたって発生する課題
- 解決する技術の1つ 「Istio」
Microservice化していくにあたって発生する課題¶
マイクロサービス化が進むと1つのシステムを複数の細かいコンポーネントにわけ、独立したサービスとして迅速にデプロイできるようになり、
その反面、モノリスなアプリケーションでは問題とならなかったサービス間の接続、モニタリング、通信の制御、エンドツーエンドの認証などが課題として顕在化してきます。
マイクロサービスを実現するためには上記の課題を解決する必要があります。
解決する技術の1つ 「Istio」¶
ここでは上記の課題を解決するための」Istio」について紹介します。
モノリスなアプリケーションから分散型・コンポーネントに分割されたアプリケーションへコンポーネント分割際に発生する課題に対して有効です。
最初はモノリスなアプリケーションをそのままコンテナ化し徐々にコンポーネントに分けていく、そしてサービス間通信をうまくやるためのServiceMeshとして開発されました。
ポイントはアプリケーションに影響なくIstioを導入できます。
さらなる進化¶
- マルチクラウド化
- ハイブリッドクラウド化
References¶
コマンドリファレンス¶
kubectlの使い方・本家へのリンク¶
公式ガイドへのリンクです。 詳細や使い方等については以下ページを見ることをおすすめします。 このページではよく使うコマンドについてユースケースでまとめました。
- https://kubernetes.io/docs/reference/kubectl/overview/
- https://kubernetes.io/docs/reference/kubectl/cheatsheet/
- https://kubernetes.io/docs/tasks/debug-application-cluster/debug-application-introspection/
- https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/
デプロイメントの実施¶
kubectl create/apply/patch/replaceを使用します。
それぞれ便利な点・留意する点があります。
kubectl create デプロイメントの基本系、マニフェストファイルを指定してデプロイし、新規に行う場合に使用します。
$ kubectl create -f deployment.yaml
kubectl applyはcreate/replaceを包含できます。差分反映のアルゴリズムを理解して利用しましょう。 applyの動きとしてはすでにデプロイされていれば更新を行い、デプロイされていなければ新規作成の動きをします。
$ kubectl apply -f deployment.yaml
kubectl replace は稼働中のアプリケーションに対して動的に定義を反映する。
$ kubectl apply -f deployment.yaml
kubectl patch は稼働中のアプリケーションに対して、一部のフィールドを書き換える用途に使用。
状況確認¶
基本形としては kubectl get オブジェクト名
と kubectl describe オブジェクト名
になります。
以下は kubectl get
ですが、get
を describe
に変更することで詳細な情報が確認できるようになります。
よく使うものとしては以下の通りです。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
wordpress-mysql-58cf8dc9f9-t2wnr 1/1 Running 0 2d
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10d
wordpress-mysql ClusterIP None <none> 3306/TCP 2d
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
wordpress-mysql 1 1 1 1 2d
ネームスペースを指定する場合は -n
オプション、または --all-namespaces
で全ネームスペースのオブジェクトを確認できます。
$ kubectl get all -n ネームスペース名
マニフェストファイルを使用している場合は get
の引数に -f マニフェストファイル
を指定すると関連するオブジェクトをすべて表示してくれます。
$ kubectl get -f deployment.yaml
現状のオブジェクトをすべて確認する場合はオブジェクトを指定する箇所に all
を設定するとすべてのオブジェクトを確認できます。
$ kubectl get all [-n ネームスペース名]
すべてのネームスペースのすべてのオブジェクトを確認したい場合は以下のとおりです。
$ kubectl get all --all-namespaces
マニフェストファイルを使用したオブジェクトの確認もできます。
-f
オプションを使用してデプロイ時に使用したマニフェストファイルを指定すると関連するオブジェクトをすべて表示します。
$ kubectl get -f wordpress-mysql-deploy.yaml
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/wordpress-mysql ClusterIP None <none> 3306/TCP 2d
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc/mysql-pv-claim Bound default-mysql-pv-claim-b5e95 20Gi RWO ontap-gold 2d
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/wordpress-mysql 1 1 1 1 2d
問題の特定方法について¶
マニフェストを
kubectl get
と kubectl describe
, kubectl logs
を組み合わせて問題箇所を特定していきます。
よく使うコマンド¶
- kubectl describe オブジェクト名
- kubectl describe -f deployment.yaml
トラブルシュートの流れ¶
問題箇所の特定
kubectl get -f deployment.yaml
で予期しない動作をしている箇所を発見- kubectl describe -f deployment.yaml
うまく行っていない箇所が分かれば該当のPodを確認する
- kubectl logs pod ポッド名
- 3rd party製の
stern
というツールもあります。こちらは複数のPodに対してkubectl logs
を実行する動きをします。非常に便利なものになります。
取得できた情報を元に対応実施
- マニフェストファイルの修正
このドキュメントは整備中です。
用語集¶
本ラボで出てくる単語集です。
おもにk8s関連の用語になります。 (version1.9時点)
用語 | 略称 | 分類 | 説明 |
---|---|---|---|
Deployment | deploy | kubernetes | アプリケーションをデプロイする時に使うもの。デプロイの管理やレプリカの管理を行う。 |
Service | svc | kubernetes | アプリケーションをkubernetesクラスタ外に公開するときに使用する。 |
Ingress | ing | kubernetes | アプリケーションをkubernetesクラスタ外に公開するときに使用する。Serviceとの違いはIngressは、Serviceの前段に配置されServiceへのアクセスルールを定義する。 |
NodePort | 特になし | kubernetes | アプリケーションをkubernetesクラスタ外に公開するときに使用する。各k8sノードでポートを解放しアクセスできるようする。接続したノードにポッドがなければ適切なノードに転送してアクセス可能にする。 |
LoadBalancer | 特になし | kubernetes | アプリケーションをkubernetesクラスタ外に公開するときに使用する。デプロイ時にロードバランサーサービスに自動登録します。クラウドサービス、オンプレミスでは一部のプラットフォームで対応しています。 |
ClusterIP | 特になし | kubernetes | アプリケーションをkubernetesクラスタ内に公開するときに使用する。 |
- Pod
- PersistentVolume
- PersistentVolumeClaim
- StorageClass
- Provisioner
- DevicePlugin
- ContainerStorageInterface(CSI)
- ContainerNetworkInterface(CNI)
- ConfigMap
- Secret
NetApp用語
- StorageVirtualMachine(SVM)
- Logical interface(LIF)
- vsadmin SVM管理者
References¶
サンプルアプリケーション¶
- Mocアプリ(Rails) https://github.com/renjikari/moc_app
- https://qiita.com/renjikari/items/d502730b687c19993579
- https://github.com/SecureSkyTechnology/BadLibrary/tree/master/src
- OracleRAC https://github.com/Seth-Miller/12c-rac-docker
- kubernetes examples https://github.com/kubernetes/examples
- Microservices デモ集 https://github.com/microservices-demo/microservices-demo
- Postgress https://github.com/paunin/PostDock
- JHipSter https://www.jhipster.tech/
Kubernetes¶
Kubernetes Helm¶
Test tools¶
CI/CD for kubernetes applications¶
- JenkinsX http://jenkins-x.io/
- Skaffolld https://github.com/GoogleCloudPlatform/skaffold
- Jenkins on GCP https://cloud.google.com/solutions/jenkins-on-kubernetes-engine-tutorial
- Pipeline https://cloud.google.com/solutions/continuous-delivery-jenkins-kubernetes-engine
- GitOps https://www.weave.works/blog/gitops-high-velocity-cicd-for-kubernetes
Kubernets Network (Expose application for external)¶
NetApp demo¶
コンテナデザインパターン¶
コンテナストレージの選択¶
Ingressを導入する¶
Level1,2ではデプロイしたアプリケーションが配置されているノードのIPに対してアクセスして稼働を確認していました。 ここからは外部にアプリケーションを公開しアクセスする方法を使用します。
具体的にはServiceを定義する際に指定する「type」が複数提供されています。
- ClusterIP
- NodePort
- LoadBalancer
- https://medium.com/@maniankara/kubernetes-tcp-load-balancer-service-on-premise-non-cloud-f85c9fd8f43c
- https://kubernetes.io/docs/concepts/services-networking/service/
今回はServiceのtypeをNodePortとして、Serviceの前段にIngressを配置する構成とします。 Ingressを使用してアプリケーションを外部に公開します。 IngressはL7ロードバランサーのような動きをします。
Ingress用のネームスペースを作成¶
Nginx Ingressをデプロイするネームスペースを作成します。
kind: Namespace
apiVersion: v1
metadata:
name: ingress
以下のコマンドでネームスペースを作成します。
$ kubectl create -f ingress-ns.yaml
namespace "ingress" created
Nginx Ingressのデプロイメント¶
helm chartを使ったNginx Ingressのデプロイメントです。
–dry-run を付与してhelmを実行することでドライランモードで実行することが可能です。
$ helm install stable/nginx-ingress --name nginx-ingress --set rbac.create=true --namespace ingress
NAME: nginx-ingress
LAST DEPLOYED: Mon Apr 9 13:58:29 2018
NAMESPACE: ingress
STATUS: DEPLOYED
RESOURCES:
==> v1/ServiceAccount
NAME SECRETS AGE
nginx-ingress 1 0s
==> v1beta1/ClusterRoleBinding
NAME AGE
nginx-ingress 0s
==> v1beta1/Role
NAME AGE
nginx-ingress 0s
==> v1beta1/RoleBinding
NAME AGE
nginx-ingress 0s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-controller LoadBalancer 10.96.106.165 <pending> 80:32065/TCP,443:32049/TCP 0s
nginx-ingress-default-backend ClusterIP 10.101.0.249 <none> 80/TCP 0s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-ingress-controller 1 1 1 0 0s
nginx-ingress-default-backend 1 1 1 0 0s
==> v1/ConfigMap
NAME DATA AGE
nginx-ingress-controller 1 0s
==> v1beta1/PodDisruptionBudget
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
nginx-ingress-controller 1 N/A 0 0s
nginx-ingress-default-backend 1 N/A 0 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-5475585cc9-q5ckc 0/1 ContainerCreating 0 0s
nginx-ingress-default-backend-956f8bbff-5znnc 0/1 ContainerCreating 0 0s
==> v1beta1/ClusterRole
NAME AGE
nginx-ingress 0s
NOTES:
The nginx-ingress controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace ingress get services -o wide -w nginx-ingress-controller'
An example Ingress that makes use of the controller:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: example
namespace: foo
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: exampleService
servicePort: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls
If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls
Ingressを作成するサンプルです。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: mynginx-ingress
spec:
rules:
- host: user10.netapp.local
http:
paths:
- backend:
serviceName: mynginx
servicePort: 80
path: /
上記のマニフェストファイルをインプットとして、Ingressを作成します。
$ kubectl create -f ingress-controller.yaml
ingress.extensions "mynginx-ingress" created
$ kubectl get ing
NAME HOSTS ADDRESS PORTS AGE
mynginx-ingress user10.netapp.local 80 51s
Ingressが作成されると、「spec - rules - host」で指定したホスト名でアクセス出来るようになります。 以下の確認では簡易的にcurlコマンドでipとホスト名をマッピングしていますが、通常はDNSへAレコードを登録します。
$ curl -L --resolve user10.netapp.local:80:10.244.0.3 http://user10.netapp.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
今回のサンプルではDNS登録することとの違いがわからないかもしれませんが、複数のサービスのエンドポイントを統一出来るようになります。
やるべきこと一覧¶
このドキュメント全体のTODOをまとめたもの
DesignDoc¶
Design: kubernetes クラスタの設計要素について¶
ラボ環境を作成する際に検討したことやなぜそのようなジャッジをしたかのメモを残す場所
ネットワーク設計¶
マルチクラスタ構成時のネットワーク構成について マルチテナントはどうする?
ストレージ設計¶
管理ポートのネットワークはどうするか?
アーキテクチャとして、cluster管理 LIF を公開するか?それともSVM管理LIFか?
- マルチテナントを構成するのであれば k8s クラスタ単位にSVMを割り当てるデザインとする。マネジメントもSVMをユーザに渡す。
StorageClass までを管理者側で作成
PersistentVolumeClaim は開発者が作成するが、ある程度のパターンはカタログ化して提供する。
無制限に作られてしまうと困るので、k8s 側で Storage Quota を設定、Namespace 毎に指定。ストレージ側では設定なし。 https://kubernetes.io/docs/concepts/policy/resource-quotas/