NetApp Digital Transformation Lab (NDX) (formerly Data Technology Lab Guide)¶
はじめに¶
目的¶
- デジタルトランスフォーメーションを支える根幹技術とNetApp製品を組み合わせることによる価値を触りながら体験
- 特定のシナリオに沿った関連技術の組み合わせ検証
- Labを通じての技術者コミュニティの創出
Contents¶
Level 0: 環境の確認・基本操作¶
目的・ゴール: ラボを実施する環境の確認¶
本ラボではkubernetesクラスタへの接続確認と稼働確認を行うことが目的です。
ガイドの中では以下を確認しています。
- ラボを実施する環境の構成理解
- 環境への接続確認
- kubernetesの基本操作を確認
流れ¶
- ユーザIDの確認
- 環境へログイン
- 基本コマンド確認、k8s へアプリケーションデプロイ
kubernetes環境へのログイン¶
各自配布されている接続先情報にログイン出来るかを確認してください。
kubernetesにデプロイ¶
kubernetes基本操作¶
必要となるコマンドラインツールがインストールされていることを確認します。
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.2", GitCommit:"bb9ffb1654d4a729bb4cec18ff088eacc153c239", GitTreeState:"clean", BuildDate:"2018-08-07T23:17:28Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.2", GitCommit:"bb9ffb1654d4a729bb4cec18ff088eacc153c239", GitTreeState:"clean", BuildDate:"2018-08-07T23:08:19Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
次にクラスタを形成するノードを確認します。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 1d v1.11.2
node0 Ready <none> 1d v1.11.2
node1 Ready <none> 1d v1.11.2
node2 Ready <none> 1d v1.11.2
デプロイメント¶
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にpushすることもできます。
DockerHub へログイン¶
DockerHubにアカウントがあることが前提です。
$ docker login
ユーザ名、パスワードを入力
$ docker image push アカウント名/コンテナイメージ名:タグ名
Private registry (GitLab) を使う場合¶
private registry を使う場合はGitLabへログインし、プロジェクトを作成します。
GitLab URL: http://gitlab.gitlab.ndxlab.net
プロジェクトを作成するとコンテナイメージのレジストリも使用できるようになります。

Dockerfileを含んだソースをgitリポジトリにpushすると自動で以下のようなビルド、レジストリへのpushの手順が提示されます。 プライベートレジストリのURLも手順内に記載されます。

Dockerイメージのビルド、pushのサンプルは以下の通りです。
$ docker build -t レジストリURL/アカウント名/コンテナイメージ名:タグ名 $ docker push レジストリURL/アカウント名/コンテナイメージ名:タグ名
アプリケーションのマニフェストファイルを作成してデプロイ¶
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 provisionerである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インストール¶
バイナリをダウンロードしてインストールします。(例はバージョン18.07)
バックエンドストレージのための setup/backend.json
を編集します。
$ wget https://github.com/NetApp/trident/releases/download/v18.07.0/trident-installer-18.07.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"
}
tridentctl
ユーティリティではドライランモードとデバッグモードがオプションで指定できます。
2つを設定し、実行すると以下のように必要事項を事前チェックし、その内容をすべて標準出力にプリントします。
まずは、ドライランモードで実行し問題ないことを確認します。以下の出力結果はユーザ14で実施した場合です。
$ ./tridentctl install --dry-run -n trident -d
DEBU Initialized logging. logLevel=debug
DEBU Running outside a pod, creating CLI-based client.
DEBU Initialized Kubernetes CLI client. cli=kubectl flavor=k8s namespace=default version=1.11.0
DEBU Validated installation environment. installationNamespace=trident kubernetesVersion=
DEBU Parsed requested volume size. quantity=2Gi
DEBU Dumping RBAC fields. ucpBearerToken= ucpHost= useKubernetesRBAC=true
DEBU Namespace does not exist. namespace=trident
DEBU PVC does not exist. pvc=trident
DEBU PV does not exist. pv=trident
INFO Starting storage driver. backend=/home/localadmin/manifest/trident/trident-installer/setup/backend.json
DEBU config: {"backendName":"NFS_ONTAP_Backend","dataLIF":"192.168.14.200","managementLIF":"192.168.14.200","password":"netapp123","storageDriverName":"ontap-nas","svm":"svm14","username":"vsadmin","version":1}
DEBU Storage prefix is absent, will use default prefix.
DEBU Parsed commonConfig: {Version:1 StorageDriverName:ontap-nas BackendName:NFS_ONTAP_Backend Debug:false DebugTraceFlags:map[] DisableDelete:false StoragePrefixRaw:[] StoragePrefix:<nil> SerialNumbers:[] DriverContext:}
DEBU Initializing storage driver. driver=ontap-nas
DEBU Addresses found from ManagementLIF lookup. addresses="[192.168.14.200]" hostname=192.168.14.200
DEBU Using specified SVM. SVM=svm14
DEBU ONTAP API version. Ontapi=1.130
WARN Could not determine controller serial numbers. API status: failed, Reason: Unable to find API: system-node-get-iter, Code: 13005
DEBU Configuration defaults Encryption=false ExportPolicy=default FileSystemType=ext4 NfsMountOptions="-o nfsvers=3" SecurityStyle=unix Size=1G SnapshotDir=false SnapshotPolicy=none SpaceReserve=none SplitOnClone=false StoragePrefix=trident_ UnixPermissions=---rwxrwxrwx
DEBU Data LIFs dataLIFs="[192.168.14.200]"
DEBU Found NAS LIFs. dataLIFs="[192.168.14.200]"
DEBU Addresses found from hostname lookup. addresses="[192.168.14.200]" hostname=192.168.14.200
DEBU Found matching Data LIF. hostNameAddress=192.168.14.200
DEBU Configured EMS heartbeat. intervalHours=24
DEBU Read storage pools assigned to SVM. pools="[aggr1_01 aggr2_01]" svm=svm14
DEBU Read aggregate attributes. aggregate=aggr1_01 mediaType=ssd
DEBU Read aggregate attributes. aggregate=aggr2_01 mediaType=hdd
DEBU Storage driver initialized. driver=ontap-nas
INFO Storage driver loaded. driver=ontap-nas
INFO Dry run completed, no problems found.
ドライランモードで実施すると最後に問題ない旨(INFO Dry run completed, no problems found.) が表示されれば、インストールに必要な事前要件を満たしていることが確認できます。
上記の状態まで確認できたら実際にインストールを実施します。
$ ./tridentctl install -n trident -d
DEBU Initialized logging. logLevel=debug
DEBU Running outside a pod, creating CLI-based client.
DEBU Initialized Kubernetes CLI client. cli=kubectl flavor=k8s namespace=default version=1.11.0
DEBU Validated installation environment. installationNamespace=trident kubernetesVersion=
DEBU Parsed requested volume size. quantity=2Gi
DEBU Dumping RBAC fields. ucpBearerToken= ucpHost= useKubernetesRBAC=true
DEBU Namespace does not exist. namespace=trident
DEBU PVC does not exist. pvc=trident
DEBU PV does not exist. pv=trident
INFO Starting storage driver. backend=/home/localadmin/manifest/trident/trident-installer/setup/backend.json
DEBU config: {"backendName":"NFS_ONTAP_Backend","dataLIF":"192.168.14.200","managementLIF":"192.168.14.200","password":"netapp123","storageDriverName":"ontap-nas","svm":"svm14","username":"vsadmin","version":1}
DEBU Storage prefix is absent, will use default prefix.
DEBU Parsed commonConfig: {Version:1 StorageDriverName:ontap-nas BackendName:NFS_ONTAP_Backend Debug:false DebugTraceFlags:map[] DisableDelete:false StoragePrefixRaw:[] StoragePrefix:<nil> SerialNumbers:[] DriverContext:}
DEBU Initializing storage driver. driver=ontap-nas
DEBU Addresses found from ManagementLIF lookup. addresses="[192.168.14.200]" hostname=192.168.14.200
DEBU Using specified SVM. SVM=svm14
DEBU ONTAP API version. Ontapi=1.130
WARN Could not determine controller serial numbers. API status: failed, Reason: Unable to find API: system-node-get-iter, Code: 13005
DEBU Configuration defaults Encryption=false ExportPolicy=default FileSystemType=ext4 NfsMountOptions="-o nfsvers=3" SecurityStyle=unix Size=1G SnapshotDir=false SnapshotPolicy=none SpaceReserve=none SplitOnClone=false StoragePrefix=trident_ UnixPermissions=---rwxrwxrwx
DEBU Data LIFs dataLIFs="[192.168.14.200]"
DEBU Found NAS LIFs. dataLIFs="[192.168.14.200]"
DEBU Addresses found from hostname lookup. addresses="[192.168.14.200]" hostname=192.168.14.200
DEBU Found matching Data LIF. hostNameAddress=192.168.14.200
DEBU Configured EMS heartbeat. intervalHours=24
DEBU Read storage pools assigned to SVM. pools="[aggr1_01 aggr2_01]" svm=svm14
DEBU Read aggregate attributes. aggregate=aggr1_01 mediaType=ssd
DEBU Read aggregate attributes. aggregate=aggr2_01 mediaType=hdd
DEBU Storage driver initialized. driver=ontap-nas
INFO Storage driver loaded. driver=ontap-nas
INFO Starting Trident installation. namespace=trident
DEBU Created Kubernetes object by YAML.
INFO Created namespace. namespace=trident
DEBU Deleted Kubernetes object by YAML.
DEBU Deleted cluster role binding.
DEBU Deleted Kubernetes object by YAML.
DEBU Deleted cluster role.
DEBU Deleted Kubernetes object by YAML.
DEBU Deleted service account.
DEBU Created Kubernetes object by YAML.
INFO Created service account.
DEBU Created Kubernetes object by YAML.
INFO Created cluster role.
DEBU Created Kubernetes object by YAML.
INFO Created cluster role binding.
DEBU Created Kubernetes object by YAML.
INFO Created PVC.
DEBU Attempting volume create. size=2147483648 storagePool=aggr1_01 volConfig.StorageClass=
DEBU Creating Flexvol. aggregate=aggr1_01 encryption=false exportPolicy=default name=trident_trident securityStyle=unix size=2147483648 snapshotDir=false snapshotPolicy=none snapshotReserve=0 spaceReserve=none unixPermissions=---rwxrwxrwx
DEBU SVM root volume has no load-sharing mirrors. rootVolume=svm_root
DEBU Created Kubernetes object by YAML.
INFO Created PV. pv=trident
INFO Waiting for PVC to be bound. pvc=trident
DEBU PVC not yet bound, waiting. increment=282.430263ms pvc=trident
DEBU PVC not yet bound, waiting. increment=907.038791ms pvc=trident
DEBU PVC not yet bound, waiting. increment=1.497234254s pvc=trident
DEBU PVC not yet bound, waiting. increment=1.182346358s pvc=trident
DEBU PVC not yet bound, waiting. increment=3.794274009s pvc=trident
DEBU Logged EMS message. driver=ontap-nas
DEBU PVC not yet bound, waiting. increment=2.554707984s pvc=trident
DEBU Created Kubernetes object by YAML.
INFO Created Trident deployment.
INFO Waiting for Trident pod to start.
DEBU Trident pod not yet running, waiting. increment=481.632837ms
DEBU Trident pod not yet running, waiting. increment=848.840617ms
DEBU Trident pod not yet running, waiting. increment=1.171028148s
DEBU Trident pod not yet running, waiting. increment=871.68468ms
DEBU Trident pod not yet running, waiting. increment=2.784723303s
DEBU Trident pod not yet running, waiting. increment=3.037298468s
DEBU Trident pod not yet running, waiting. increment=7.540652793s
DEBU Trident pod not yet running, waiting. increment=12.611925219s
DEBU Trident pod not yet running, waiting. increment=18.389729895s
INFO Trident pod started. namespace=trident pod=trident-6946fdf6d8-8cb8q
INFO Waiting for Trident REST interface.
DEBU Invoking tunneled command: kubectl exec trident-6946fdf6d8-8cb8q -n trident -c trident-main -- tridentctl -s 127.0.0.1:8000 version -o json
INFO Trident REST interface is up. version=18.07.0
INFO Trident installation succeeded.
「INFO Trident installation succeeded.」が出力されればインストール成功です。
また、問題が発生した場合には tridentctl
を使用して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へバックエンドストレージの登録¶
インストールが完了したらtridentのバージョンを確認します。
$ ./tridentctl version -n trident
+----------------+----------------+
| SERVER VERSION | CLIENT VERSION |
+----------------+----------------+
| 18.07.0 | 18.07.0 |
+----------------+----------------+
バージョンが表示されていればインストール成功です。
作成した定義ファイル、 setup/backend.json
を使用し、バックエンド登録を実行します。
まずは NFS ストレージバックエンドであるONTAPを登録します。
$ ./tridentctl -n trident create backend -f setup/backend.json
+-------------------+----------------+--------+---------+
| NAME | STORAGE DRIVER | ONLINE | VOLUMES |
+-------------------+----------------+--------+---------+
| NFS_ONTAP_Backend | ontap-nas | true | 0 |
+-------------------+----------------+--------+---------+
つづいて、iSCSI ブロック・ストレージバックエンドのSolidFireを登録します。
NFSバックエンドストレージと同様に setup
ディレクトリに solidfire-backend.json
を作成します。
基本的な設定項目としては以下の表の通りです。
パラメータ名 | 説明 | 設定内容 |
---|---|---|
Endpoint | SolidFire の管理用IPを設定(MVIP)、URL先頭にユーザーIDとパスワードを付与 | 10.128.223.240 |
SVIP | データ通信のIPを設定(クラスタで1つ) | 192.168.0.240:3260 |
TenantName | 任意の名称を設定、SolidFire側でのテナントとなる。 | 今回は環境番号とする(userXX) |
Types | ストレージカタログとしてのQoSのリストを指定 | 1つ以上のminIOPS, maxIOPS, burstIOPSを指定 |
テンプレートとなるSolidFireのバックエンド定義ファイルは以下の通りです。
{
"version": 1,
"storageDriverName": "solidfire-san",
"Endpoint": "https://ユーザ名:パスワード@マネジメント用IP/json-rpc/8.0",
"SVIP": "ストレージアクセス用IP:3260",
"TenantName": "ユーザ環境番号",
"backendName": "iSCSI_SF_Backend",
"InitiatorIFace": "default",
"UseCHAP": true,
"Types": [
{
"Type": "Bronze",
"Qos": {
"minIOPS": 1000,
"maxIOPS": 3999,
"burstIOPS": 4500
}
},
{
"Type": "Silver",
"Qos": {
"minIOPS": 4000,
"maxIOPS": 5999,
"burstIOPS": 6500
}
},
{
"Type": "Gold",
"Qos": {
"minIOPS": 6000,
"maxIOPS": 8000,
"burstIOPS": 10000
}
}
]
}
同様にバックエンド登録を実施します。
$ ./tridentctl -n trident create backend -f setup/solidfire-backend.json
+------------------+----------------+--------+---------+
| NAME | STORAGE DRIVER | ONLINE | VOLUMES |
+------------------+----------------+--------+---------+
| iSCSI_SF_Backend | solidfire-san | true | 0 |
+------------------+----------------+--------+---------+
今までに登録したストレージバックエンドを確認します。
$ ./tridentctl get backend -n trident
+-------------------+----------------+--------+---------+
| NAME | STORAGE DRIVER | ONLINE | VOLUMES |
+-------------------+----------------+--------+---------+
| NFS_ONTAP_Backend | ontap-nas | true | 0 |
| iSCSI_SF_Backend | solidfire-san | true | 0 |
+-------------------+----------------+--------+---------+
注釈
tridentctl
ユーティリティにはアンインストール用のサブコマンドがあります。
以下のように -a
オプションを付与して実行すると生成した管理用のetcdのデータなどすべてを削除した上でアンインストールします。
インストール実行時に失敗したときなど、クリーンに再インストールしたい場合に使います。
$ ./tridentctl uninstall -n trident -a
StorageClassの定義¶
StorageClassを定義して、ストレージのサービスカタログを作りましょう。
Trident v18.07 ではStorageClassを作成するときに以下の属性を設定できます。 これらの属性のパラメータを組み合わせてストレージサービスをデザインします。
設定可能な属性 | 例 |
---|---|
性能に関する属性 | メデイアタイプ(hdd, hybrid, ssd)、プロビジョニングのタイプ(シン、シック)、IOPS |
データ保護・管理に関する属性 | スナップショット有無、クローニング有効化、暗号化の有効化 |
バックエンドのストレージプラットフォーム属性 | ontap-nas, ontap-nas-economy, ontap-nas-flexgroup, ontap-san, solidfire-san, eseries-iscsi |
全てのパラメータ設定については以下のURLに記載があります。
NFSバックエンドのONTAPでのStorageClass¶
ストレージ構成は以下の通りです。 今回、意識する必要があるところは異なるメディアタイプ(HDDとSSD)のアグリゲートを保有しているところです。
各SVMにHDD, SSDのアグリゲートを割り当て済み
- aggr1_01:SSDのアグリゲート
- aggr2_01:HDDのアグリゲート
以下のようなイメージでStoageClassを作成しましょう。
- DB 用の高速領域: SSD を使ったストレージサービス
- Web コンテンツ用のリポジトリ: HDDを使ったストレージサービス
以下は上記の「DB 用の高速領域」の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
同様にブロックデバイスバックエンドとして設定したSolidFireに対応するStorageClassを作成します。
バックエンド登録時に3つの性能別のQoSを作成しました。
それぞれに該当するStoageClassを作成します。StorageClassで指定されたIOPSを実現できるバックエンドのQoSがボリューム作成時に自動設定されます。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: solidfire-bronze
provisioner: netapp.io/trident
parameters:
backendType: "solidfire-san"
IOPS: "1500"
fsType: "ext4"
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: solidfire-silver
provisioner: netapp.io/trident
parameters:
backendType: "solidfire-san"
IOPS: "4000"
fsType: "ext4"
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: solidfire-gold
provisioner: netapp.io/trident
parameters:
backendType: "solidfire-san"
IOPS: "8000"
fsType: "ext4"
以降のセクションではここまでで作成したStorageClassを適切に使い分けてすすめましょう。
注釈
デフォルトのStorageClassの設定
StorageClassは記載がないときに使用するStorageClassを指定できます。
kubectl patch storageclass ストレージクラス名 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
Persistent Volume Claimの作成¶
アプリケーションで必要とされる永続化領域の定義をします。 PVCを作成時に独自の機能を有効化することができます。
データの保管ポリシー、データ保護ポリシー、SnapShotの取得ポリシー、クローニングの有効化、暗号化の有効化などを設定できます。
一覧については以下のURLに記載があります。
metadata.annotation
配下に記述することで様々な機能を使用することが可能となります。
デプロイ用のマニフェストファイルに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
デプロイメント実施¶
上記のPVCの設定が終わったら再度アプリケーションをデプロイします。
その後、アプリケーションからデータを保存するようオペレーションを行います。 WordPressであれば記事を投稿することで簡単に確認ができます。
アプリケーションの停止・起動¶
永続化されていることを確認するため、一度アプリケーションを停止します。
Deploymentで必要となるポッドは起動するような設定になっているため、
簡単にアプリケーションの停止・起動を行う方法として Deployment
配下の Pod
を削除する方法がとれます。
$ kubectl delete pod -l "ラベル名"
$ kubectl get deploy
実行例は以下の通りです。
$ kubectl delete pod -l app=wordpress
pod "wordpress-5bc75fd7bd-kzc5l" deleted
pod "wordpress-mysql-565494758-jjdl4" deleted
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
wordpress 1 1 1 0 31d
wordpress-mysql 1 1 1 0 31d
DeploymentによってPodの起動数は管理されるため新たにPodが起動します。
AVAILABLE
の数が正常になるまで待ちましょう。
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
wordpress 1 1 1 1 31d
wordpress-mysql 1 1 1 1 31d
再デプロイメント後の確認¶
再起動したPodに対して永続化されたデータが使用されていることを確認します。 2つの視点から確認したいと思います。
- アプリケーションであれば再度ログインして保存したデータを確認します。
- バックエンドストレージに動的にボリュームが作成されていることを確認します。
$ ssh vsadmin@192.168.XX.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
を介してクローン機能を利用できます。
引数にPVC名を指定します。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: basicclone
annotations:
trident.netapp.io/cloneFromPVC: database (<-ここにクローンしたい既存のPVC名(ボリューム名)を記述)
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: ontap-gold
ここではサンプルでPVC Cloning を活用したOracle Databaseを複数デプロイするデモ動画をご覧ください。
クローニング技術によって実現可能なこと¶
クローニング技術はシンプルですが非常に多く用途で使用することができます。 例としてあげられるのが以下の用途です。
- プレビルド環境の高速展開
- 本番環境に影響せずに大規模な並列テスト
- 運用時のデータリストアの高速化、瞬時に論理障害を戻す
Tridentの18.07でのアップデート: CSI (Container Storage Interface)への対応¶
最新のTridentではCSIモードでのデプロイが可能となっています。(インストール時に --csi
を付与する)
CSIは仕様自体がまだαステージということもあり実験的なモードですが、いち早くCSIをお試しいただくことが可能となっています。
- Trident CSI モードでの動作:https://netapp-trident.readthedocs.io/en/latest/kubernetes/trident-csi.html
- Trident CSI に書かれた記事: https://netapp.io/2018/07/03/netapp-trident-and-the-csi-oh-my/
CSI自体についてはこちら - https://kubernetes.io/blog/2018/01/introducing-container-storage-interface/
注釈
理論的にはCSIの仕様でドライバを実装すれば、そのドライバはkubernetes、Mesos, Docker, Cloud Foundryなど CSIを実装したコンテナオーケストレーターから使用できるようになります。
まとめ¶
アプリケーションに対して動的に永続化領域をプロビジョニングしデータの永続化を実現しました。
今回は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はGitLabを共有で準備していますが、使いなれているサービス(GitHub等)があればそちらを使って頂いても構いません。 まずは、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
を LoadBalancer
としてしてデプロイすると external-ipが付与される環境となっています。(MetalLBをデプロイ済みです。)
2つ目が Ingress
を使った公開です。IngressをJenkinsのHelmチャートを使ってデプロイするためには「Master.Ingress.Annotations」、「Master.ServiceType」を変更しデプロイします。
簡易的にデプロイをためしてみたい方は1つ目の LoadBalancer
を使ったやり方を実施、新しい概念であるIngressを使った方法を実施したい方は2つ目を選択しましょう。
どちらの方法の場合も、以下のvalues.yamlをカスタマイズしてデプロイします。 このレベルではJenkinsをデプロイするのが目的ではなくCI/CDパイプラインを作成するのが目的であるため、デプロイ用のyamlファイルを準備しました。
また、このvalues.yamlでは永続化ストレージが定義されていないため、Level2で作成したStorageClassを使用し動的にプロビジョニングをするように変更しましょう。
StorageClassには環境に作成したStorageClassを設定します。このサンプルでは "ontap-gold"を設定してあります。
また、Kubernetes上でCI/CDパイプラインを作成するため Kubernetes-plugin
も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>
resources:
requests:
cpu: "50m"
memory: "256Mi"
limits:
cpu: "2000m"
memory: "2048Mi"
# 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"
# Enable pod security context (must be `true` if RunAsUser or FsGroup are set)
UsePodSecurityContext: true
# 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
# Enable Kubernetes Liveness and Readiness Probes
# ~ 2 minutes to allow Jenkins to restart when upgrading plugins. Set ReadinessTimeout to be shorter than LivenessTimeout.
HealthProbes: true
HealthProbesLivenessTimeout: 90
HealthProbesReadinessTimeout: 60
HealthProbeLivenessFailureThreshold: 12
SlaveListenerPort: 50000
DisabledAgentProtocols:
- JNLP-connect
- JNLP2-connect
CSRF:
DefaultCrumbIssuer:
Enabled: true
ProxyCompatability: true
CLI: false
# 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.12.3
- workflow-job:2.24
- workflow-aggregator:2.5
- credentials-binding:1.16
- git:3.9.1
- blueocean:1.8.2
- ghprb:1.40.0
# 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: {}
PodAnnotations: {}
Ingress:
ApiVersion: extensions/v1beta1
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
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "200m"
memory: "256Mi"
# You may want to change this to true while testing a new image
AlwaysPullImage: false
# Controls how slave pods are retained after the Jenkins build completes
# Possible values: Always, Never, OnFailure
PodRetention: Never
# 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>ls
## 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: "ontap-gold"
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 v1, v1beta1, or v1alpha1)
apiVersion: v1
# Role reference
roleRef: cluster-admin
# Role kind (RoleBinding or ClusterRoleBinding)
roleBindingKind: ClusterRoleBinding
実行イメージとしては以下の通りです。
$ helm --namespace jenkins --name jenkins -f ./jenkins-values.yaml install stable/jenkins --debug
[debug] Created tunnel using local port: '44511'
[debug] SERVER: "127.0.0.1:44511"
[debug] Original chart version: ""
[debug] Fetched stable/jenkins to /home/localadmin/.helm/cache/archive/jenkins-0.16.20.tgz
[debug] CHART PATH: /home/localadmin/.helm/cache/archive/jenkins-0.16.20.tgz
NAME: jenkins
REVISION: 1
RELEASED: Mon Aug 27 23:54:09 2018
CHART: jenkins-0.16.20
USER-SUPPLIED VALUES:
Agent:
AlwaysPullImage: false
Component: jenkins-slave
Enabled: true
Image: jenkins/jnlp-slave
ImageTag: 3.10-1
NodeSelector: {}
PodRetention: Never
Privileged: false
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 200m
memory: 256Mi
volumes: null
Master:
AdminUser: admin
CLI: false
CSRF:
DefaultCrumbIssuer:
Enabled: true
ProxyCompatability: true
Component: jenkins-master
CustomConfigMap: false
DisabledAgentProtocols:
- JNLP-connect
- JNLP2-connect
HealthProbeLivenessFailureThreshold: 12
HealthProbes: true
HealthProbesLivenessTimeout: 90
HealthProbesReadinessTimeout: 60
Image: jenkins/jenkins
ImagePullPolicy: Always
ImageTag: lts
Ingress:
Annotations: null
ApiVersion: extensions/v1beta1
TLS: null
InitScripts: null
InstallPlugins:
- kubernetes:1.12.3
- workflow-job:2.24
- workflow-aggregator:2.5
- credentials-binding:1.16
- git:3.9.1
- blueocean:1.4.1
- ghprb:1.40.0
LoadBalancerSourceRanges:
- 0.0.0.0/0
Name: jenkins-master
NodeSelector: {}
PodAnnotations: {}
ServiceAnnotations: {}
ServicePort: 8080
ServiceType: LoadBalancer
SlaveListenerPort: 50000
SlaveListenerServiceAnnotations: {}
SlaveListenerServiceType: ClusterIP
Tolerations: {}
UsePodSecurityContext: true
UseSecurity: true
resources:
limits:
cpu: 2000m
memory: 2048Mi
requests:
cpu: 50m
memory: 256Mi
NetworkPolicy:
ApiVersion: extensions/v1beta1
Enabled: false
Persistence:
AccessMode: ReadWriteOnce
Annotations: {}
Enabled: true
Size: 8Gi
StorageClass: ontap-gold
mounts: null
volumes: null
rbac:
apiVersion: v1
install: false
roleBindingKind: ClusterRoleBinding
roleRef: cluster-admin
serviceAccountName: default
COMPUTED VALUES:
Agent:
AlwaysPullImage: false
Component: jenkins-slave
Enabled: true
Image: jenkins/jnlp-slave
ImageTag: 3.10-1
NodeSelector: {}
PodRetention: Never
Privileged: false
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 200m
memory: 256Mi
volumes: null
Master:
AdminUser: admin
CLI: false
CSRF:
DefaultCrumbIssuer:
Enabled: true
ProxyCompatability: true
Component: jenkins-master
CustomConfigMap: false
DisabledAgentProtocols:
- JNLP-connect
- JNLP2-connect
HealthProbeLivenessFailureThreshold: 12
HealthProbes: true
HealthProbesLivenessTimeout: 90
HealthProbesReadinessTimeout: 60
Image: jenkins/jenkins
ImagePullPolicy: Always
ImageTag: lts
Ingress:
Annotations: null
ApiVersion: extensions/v1beta1
TLS: null
InitScripts: null
InstallPlugins:
- kubernetes:1.12.3
- workflow-job:2.24
- workflow-aggregator:2.5
- credentials-binding:1.16
- git:3.9.1
- blueocean:1.4.1
- ghprb:1.40.0
LoadBalancerSourceRanges:
- 0.0.0.0/0
Name: jenkins-master
NodeSelector: {}
PodAnnotations: {}
ServiceAnnotations: {}
ServicePort: 8080
ServiceType: LoadBalancer
SlaveListenerPort: 50000
SlaveListenerServiceAnnotations: {}
SlaveListenerServiceType: ClusterIP
Tolerations: {}
UsePodSecurityContext: true
UseSecurity: true
resources:
limits:
cpu: 2000m
memory: 2048Mi
requests:
cpu: 50m
memory: 256Mi
NetworkPolicy:
ApiVersion: extensions/v1beta1
Enabled: false
Persistence:
AccessMode: ReadWriteOnce
Annotations: {}
Enabled: true
Size: 8Gi
StorageClass: ontap-gold
mounts: null
volumes: null
rbac:
apiVersion: v1
install: false
roleBindingKind: ClusterRoleBinding
roleRef: cluster-admin
serviceAccountName: default
HOOKS:
---
# jenkins-ui-test-1g5nb
apiVersion: v1
kind: Pod
metadata:
name: "jenkins-ui-test-1g5nb"
annotations:
"helm.sh/hook": test-success
spec:
initContainers:
- name: "test-framework"
image: "dduportal/bats:0.4.0"
command:
- "bash"
- "-c"
- |
set -ex
# copy bats to tools dir
cp -R /usr/local/libexec/ /tools/bats/
volumeMounts:
- mountPath: /tools
name: tools
containers:
- name: jenkins-ui-test
image: jenkins/jenkins:lts
command: ["/tools/bats/bats", "-t", "/tests/run.sh"]
volumeMounts:
- mountPath: /tests
name: tests
readOnly: true
- mountPath: /tools
name: tools
volumes:
- name: tests
configMap:
name: jenkins-tests
- name: tools
emptyDir: {}
restartPolicy: Never
MANIFEST:
---
# Source: jenkins/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: jenkins
labels:
app: jenkins
chart: "jenkins-0.16.20"
release: "jenkins"
heritage: "Tiller"
type: Opaque
data:
jenkins-admin-password: "N3EwZWtydDAyQg=="
jenkins-admin-user: "YWRtaW4="
---
# Source: jenkins/templates/config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jenkins
data:
config.xml: |-
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
<disabledAdministrativeMonitors/>
<version>lts</version>
<numExecutors>0</numExecutors>
<mode>NORMAL</mode>
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
<denyAnonymousReadAccess>true</denyAnonymousReadAccess>
</authorizationStrategy>
<securityRealm class="hudson.security.LegacySecurityRealm"/>
<disableRememberMe>false</disableRememberMe>
<projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
<workspaceDir>${JENKINS_HOME}/workspace/${ITEM_FULLNAME}</workspaceDir>
<buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>
<markupFormatter class="hudson.markup.EscapedMarkupFormatter"/>
<jdks/>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds>
<org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud plugin="kubernetes@1.12.3">
<name>kubernetes</name>
<templates>
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
<inheritFrom></inheritFrom>
<name>default</name>
<instanceCap>2147483647</instanceCap>
<idleMinutes>0</idleMinutes>
<label>jenkins-jenkins-slave</label>
<nodeSelector></nodeSelector>
<nodeUsageMode>NORMAL</nodeUsageMode>
<volumes>
</volumes>
<containers>
<org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<name>jnlp</name>
<image>jenkins/jnlp-slave:3.10-1</image>
<privileged>false</privileged>
<alwaysPullImage>false</alwaysPullImage>
<workingDir>/home/jenkins</workingDir>
<command></command>
<args>${computer.jnlpmac} ${computer.name}</args>
<ttyEnabled>false</ttyEnabled>
# Resources configuration is a little hacky. This was to prevent breaking
# changes, and should be cleanned up in the future once everybody had
# enough time to migrate.
<resourceRequestCpu>200m</resourceRequestCpu>
<resourceRequestMemory>256Mi</resourceRequestMemory>
<resourceLimitCpu>200m</resourceLimitCpu>
<resourceLimitMemory>256Mi</resourceLimitMemory>
<envVars>
<org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<key>JENKINS_URL</key>
<value>http://jenkins:8080</value>
</org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
</envVars>
</org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
</containers>
<envVars/>
<annotations/>
<imagePullSecrets/>
<nodeProperties/>
<podRetention class="org.csanchez.jenkins.plugins.kubernetes.pod.retention.Default"/>
</org.csanchez.jenkins.plugins.kubernetes.PodTemplate></templates>
<serverUrl>https://kubernetes.default</serverUrl>
<skipTlsVerify>false</skipTlsVerify>
<namespace>jenkins</namespace>
<jenkinsUrl>http://jenkins:8080</jenkinsUrl>
<jenkinsTunnel>jenkins-agent:50000</jenkinsTunnel>
<containerCap>10</containerCap>
<retentionTimeout>5</retentionTimeout>
<connectTimeout>0</connectTimeout>
<readTimeout>0</readTimeout>
<podRetention class="org.csanchez.jenkins.plugins.kubernetes.pod.retention.Never"/>
</org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud>
</clouds>
<quietPeriod>5</quietPeriod>
<scmCheckoutRetryCount>0</scmCheckoutRetryCount>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>All</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
</views>
<primaryView>All</primaryView>
<slaveAgentPort>50000</slaveAgentPort>
<disabledAgentProtocols>
<string>JNLP-connect</string>
<string>JNLP2-connect</string>
</disabledAgentProtocols>
<label></label>
<crumbIssuer class="hudson.security.csrf.DefaultCrumbIssuer">
<excludeClientIPFromCrumb>true</excludeClientIPFromCrumb>
</crumbIssuer>
<nodeProperties/>
<globalNodeProperties/>
<noUsageStatistics>true</noUsageStatistics>
</hudson>
jenkins.model.JenkinsLocationConfiguration.xml: |-
<?xml version='1.1' encoding='UTF-8'?>
<jenkins.model.JenkinsLocationConfiguration>
<adminAddress></adminAddress>
<jenkinsUrl>http://jenkins:8080</jenkinsUrl>
</jenkins.model.JenkinsLocationConfiguration>
jenkins.CLI.xml: |-
<?xml version='1.1' encoding='UTF-8'?>
<jenkins.CLI>
<enabled>false</enabled>
</jenkins.CLI>
apply_config.sh: |-
mkdir -p /usr/share/jenkins/ref/secrets/;
echo "false" > /usr/share/jenkins/ref/secrets/slave-to-master-security-kill-switch;
cp -n /var/jenkins_config/config.xml /var/jenkins_home;
cp -n /var/jenkins_config/jenkins.CLI.xml /var/jenkins_home;
cp -n /var/jenkins_config/jenkins.model.JenkinsLocationConfiguration.xml /var/jenkins_home;
# Install missing plugins
cp /var/jenkins_config/plugins.txt /var/jenkins_home;
rm -rf /usr/share/jenkins/ref/plugins/*.lock
/usr/local/bin/install-plugins.sh `echo $(cat /var/jenkins_home/plugins.txt)`;
# Copy plugins to shared volume
cp -n /usr/share/jenkins/ref/plugins/* /var/jenkins_plugins;
plugins.txt: |-
kubernetes:1.12.3
workflow-job:2.24
workflow-aggregator:2.5
credentials-binding:1.16
git:3.9.1
blueocean:1.4.1
ghprb:1.40.0
---
# Source: jenkins/templates/test-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jenkins-tests
data:
run.sh: |-
@test "Testing Jenkins UI is accessible" {
curl --retry 48 --retry-delay 10 jenkins:8080/login
}
---
# Source: jenkins/templates/home-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: jenkins
labels:
app: jenkins
chart: "jenkins-0.16.20"
release: "jenkins"
heritage: "Tiller"
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: "8Gi"
storageClassName: "ontap-gold"
---
# Source: jenkins/templates/jenkins-agent-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: jenkins-agent
labels:
app: jenkins
chart: "jenkins-0.16.20"
component: "jenkins-jenkins-master"
spec:
ports:
- port: 50000
targetPort: 50000
name: slavelistener
selector:
component: "jenkins-jenkins-master"
type: ClusterIP
---
# Source: jenkins/templates/jenkins-master-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: jenkins
labels:
app: jenkins
heritage: "Tiller"
release: "jenkins"
chart: "jenkins-0.16.20"
component: "jenkins-jenkins-master"
spec:
ports:
- port: 8080
name: http
targetPort: 8080
selector:
component: "jenkins-jenkins-master"
type: LoadBalancer
loadBalancerSourceRanges:
- 0.0.0.0/0
---
# Source: jenkins/templates/jenkins-master-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: jenkins
labels:
heritage: "Tiller"
release: "jenkins"
chart: "jenkins-0.16.20"
component: "jenkins-jenkins-master"
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
component: "jenkins-jenkins-master"
template:
metadata:
labels:
app: jenkins
heritage: "Tiller"
release: "jenkins"
chart: "jenkins-0.16.20"
component: "jenkins-jenkins-master"
annotations:
checksum/config: f1949fdff0e0d3db7c6180357f63c007db61b13e5c107e5980a5eac982863c21
spec:
securityContext:
runAsUser: 0
serviceAccountName: "default"
initContainers:
- name: "copy-default-config"
image: "jenkins/jenkins:lts"
imagePullPolicy: "Always"
command: [ "sh", "/var/jenkins_config/apply_config.sh" ]
resources:
limits:
cpu: 2000m
memory: 2048Mi
requests:
cpu: 50m
memory: 256Mi
volumeMounts:
-
mountPath: /var/jenkins_home
name: jenkins-home
-
mountPath: /var/jenkins_config
name: jenkins-config
-
mountPath: /var/jenkins_plugins
name: plugin-dir
-
mountPath: /usr/share/jenkins/ref/secrets/
name: secrets-dir
containers:
- name: jenkins
image: "jenkins/jenkins:lts"
imagePullPolicy: "Always"
args: [ "--argumentsRealm.passwd.$(ADMIN_USER)=$(ADMIN_PASSWORD)", "--argumentsRealm.roles.$(ADMIN_USER)=admin"]
env:
- name: JAVA_TOOL_OPTIONS
value: ""
- name: JENKINS_OPTS
value: ""
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: jenkins
key: jenkins-admin-password
- name: ADMIN_USER
valueFrom:
secretKeyRef:
name: jenkins
key: jenkins-admin-user
ports:
- containerPort: 8080
name: http
- containerPort: 50000
name: slavelistener
livenessProbe:
httpGet:
path: "/login"
port: http
initialDelaySeconds: 90
timeoutSeconds: 5
failureThreshold: 12
readinessProbe:
httpGet:
path: "/login"
port: http
initialDelaySeconds: 60
# Resources configuration is a little hacky. This was to prevent breaking
# changes, and should be cleanned up in the future once everybody had
# enough time to migrate.
resources:
limits:
cpu: 2000m
memory: 2048Mi
requests:
cpu: 50m
memory: 256Mi
volumeMounts:
-
mountPath: /var/jenkins_home
name: jenkins-home
readOnly: false
-
mountPath: /var/jenkins_config
name: jenkins-config
readOnly: true
-
mountPath: /usr/share/jenkins/ref/plugins/
name: plugin-dir
readOnly: false
-
mountPath: /usr/share/jenkins/ref/secrets/
name: secrets-dir
readOnly: false
volumes:
- name: jenkins-config
configMap:
name: jenkins
- name: plugin-dir
emptyDir: {}
- name: secrets-dir
emptyDir: {}
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins
LAST DEPLOYED: Mon Aug 27 23:54:09 2018
NAMESPACE: jenkins
STATUS: DEPLOYED
RESOURCES:
==> v1/Secret
NAME TYPE DATA AGE
jenkins Opaque 2 0s
==> v1/ConfigMap
NAME DATA AGE
jenkins 5 0s
jenkins-tests 1 0s
==> v1/PersistentVolumeClaim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
jenkins Pending ontap-gold 0s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-agent ClusterIP 10.109.172.86 <none> 50000/TCP 0s
jenkins LoadBalancer 10.97.161.136 192.168.10.210 8080:30376/TCP 0s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
jenkins 1 1 1 0 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
jenkins-965668c95-7tzmc 0/1 Pending 0 0s
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. Get the Jenkins URL to visit by running these commands in the same shell:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc --namespace jenkins -w jenkins'
export SERVICE_IP=$(kubectl get svc --namespace jenkins jenkins --template "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}")
echo http://$SERVICE_IP:8080/login
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
「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のTry & Error: インストールが上手くいかない場合は?¶
values.yamlを試行錯誤しながら設定していくことになると思います。 一度デプロイメントしたHelmチャートは以下のコマンドで削除することができます。
$ helm del --purge チャート名
Helm以外でJenkinsをデプロイした場合¶
本セクションに記載してあることはオプションです。
必要に応じて実施してください。
外部にアプリケーションを公開する方法として Ingress
があります。
Helmを使ってJenkinsをインストー時にvalues.yamlで設定を行うことでIngressが作成されます。
それ以外の手法を取った場合は、kubernetesクラスタ外のネットワークからアクセスできるようにIngressを作成しアクセスする方法があります。
Ingressの導入についてはLevel4 運用編の Ingressを導入 にまとめました。
Jenkinsの設定をする¶
Gitリポジトリに変更があったら自動でテストを実行するpipelineを定義します。 そのためにはまずJenkinsでGitリポジトリに操作があった場合の動作の定義とKubernetesとの接続の設定をします。
定義出来る動作としては以下の単位が考えられます。 細かく設定することも可能です。運用に合わせた単位で設定します。
- pull request 単位
- release tag 単位
- 定期実行
前述した項目を盛り込みCI/CDパイプラインを作成しましょう。 シンプルなパイプラインからはじめ、必要に応じてステージを追加していきましょう。
Jenkins AgentをKubernetes上で実行できるようにする¶
Jenkinsからkubernetes上でJenkins agentを実行する場合にはJenkins kubernetes-plugin の導入が必要です。 通常はソースコードの取得から実施することになります。gitを使う場合であればgitのjenkins-pluginが必要です。
本ガイドで準備した values.yaml を使用している場合にはすでにどちらも導入されている状態となります。
ここでは Jenkins から kubernetesへ接続できるようにする設定を提示いたします。
Jeninsログイン後、クレデンシャルを事前に作成します。

jenkins 導入済みのネームスペースにサービスアカウントを作成します。
kubectl create clusterrolebinding jenkins --clusterrole cluster-admin --serviceaccount=jenkins:default
Configurationから「Kubernetes設定」を選択します。

ここでは必要となるパラメータを設定していきます。
- kubernetes URL: マスタのIP, 192.168.XX.10
- Kubernetes Namespace: Jenkinsをインストールしたnamespace名
- kubernetes certificate key: /etc/kubernetes/pki/apiserver.crtの内容をペースト
- Credentials: Secret を選択
Jenkins Pipelineの作成¶
- テスト実行
- アプリケーションビルド
- コンテナイメージのビルド
- レジストリへコンテナイメージのpush
- アプリケーションデプロイ
上記のようなパイプラインを作成にはJenkins pipeline機能が活用できます。
- https://jenkins.io/doc/book/pipeline/
- https://github.com/jenkinsci/kubernetes-plugin/blob/master/README.md
ここではテンプレートを準備しました、上記の様なパイプラインを実装してみましょう。 Jenkins ではパイプラインを構築するために2つの記述方法があります。
- Declarative pipeline syntax https://jenkins.io/doc/book/pipeline/#declarative-pipeline-fundamentals
- Scripted pipeline syntax https://jenkins.io/doc/book/pipeline/#scripted-pipeline-fundamentals
それぞれの違いついてはこちら。
pipeline {
agent {
kubernetes {
label 'jenkins-ci'
defaultContainer 'jnlp'
yamlFile 'KubernetesPod.yaml'
}
}
stages {
stage('Pre Build Check') {
steps {
script {
echo "Pre Build staget implement!"
}
container('busybox') {
sh 'echo Hello Container World in Pre Build Check'
}
}
}
stage('Build') {
steps {
echo "Build staget implement!"
script {
// Dockerfile 内部でdockerを導入する
// docker.build("nodejs-build-${env.BUILD_ID}").inside() {
// node -v
// }
}
}
}
stage('Test') {
steps {
echo 'Test Stage implement!'
container('kubectl') {
sh 'kubectl version'
}
}
}
stage('Deploy') {
steps {
echo 'printenv'
container('helm') {
sh 'helm version'
}
}
}
}
}
metadata:
labels:
some-label: jenkins-ci
spec:
containers:
- name: jnlp
env:
- name: CONTAINER_ENV_VAR
value: jnlp
- name: busybox
image: busybox
command:
- cat
tty: true
env:
- name: CONTAINER_ENV_VAR
value: busybox
- name: kubectl
image: lachlanevenson/k8s-kubectl:v1.8.8
command:
- cat
tty: true
env:
- name: CONTAINER_ENV_VAR
value: kubectl
- name: helm
image: lachlanevenson/k8s-helm:latest
command:
- cat
tty: true
env:
- name: CONTAINER_ENV_VAR
value: helm
Jenkins pipeline の作成が完了したら任意のGitリポジトリにpushします。 以降のJenkins Pipelineの実行にJenkinsfileを使用します。
アプリケーションの変更を検知してデプロイメント可能にする¶
CI/CDのパイプラインを作成したら実際にアプリケーションの変更をトリガー(ソースコードの変更、Gitリポジトリへのpush等)としてk8sへアプリケーションをデプロイします。
ポリシーとして大きく2つに別れます、参考までに以下に記載いたします。
- デプロイ可能な状態までにし、最後のデプロイメントは人が実施する(クリックするだけ)
- デプロイメントまでを完全自動化する
実際にkubernetes環境へのデプロイができたかの確認とアプリケーションが稼働しているかを確認します。
今回はサンプルとしてJenkinsのBlueOcean pluginを使用してPipelineを作成します。

BlueOcean plugin を使用するとウィザード形式でPipelineを作成することができます。
各入力値については以下のURLにてどのような形式で入力されるかの記載があります。
コンテナをCI/CDする方法 Helmを使ってみる¶
コンテナのCI/CDではいくつか方法があります。 ここではコンテナをCI/CDするために必要な検討事項を記載するとともに
個別のアプリケーションデプロイメントからHelm Chartを使ったデプロイメントに変更します。
作成したコンテナをHelm Chartを使ってデプロイするようにします。
Helm Chartの開発ガイドは以下のURLを確認ください。
他にも以下のようなCI/CDを行いやすくする構成管理・パッケージマネジメントのツールが存在しています。
- Kustomize
- Draft
- GitKube
- Skaffold
デプロイメントのさらなる進化¶
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が使えるようになりました。
本ラボでは簡易的なパイプラインを実際に構築しました。パイプライン内の処理については個々で実装したものから発展させ様々な処理を追加することができます。
ここまでで 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/
アプリケーション負荷に応じたスケールアップ¶
Horizontal Pod AutoScaler
に対して Vertical Pod AutoScaler
があります。
完全互換ではありませんが、Vertical Pod AutoScalerというものが k8s 1.9でalpha versionとして提供されています。 従来型のアプリケーションではスケールアウトより、スケールアップのほうが行いやすいのが一般的です。
https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler
アプリケーションの監視¶
kubernetsで監視すべき項目としてはクラスタ全体の監視とアプリケーションごとの監視になります。
- クラスタ全体の監視については後述します。
- 稼働しているアプリケーションの監視(Pod の監視)
Kubernetes クラスタの操作性を向上させる¶
Rancher でできること¶
Rancherは様々な環境のkubernetesクラスタを管理するとともに、アプリケーションの管理も行うことができます。
ここではRancherの導入から、アプリケーションのデプロイまでを簡単に実施します。
ここでいうアプリケーションとは kubernetes 上で動くものすべてです。
例えば、kubernetes クラスタを監視するソフトウェアスタック(Prometheus+Grafana+InfluxDB)をkubernetes上で簡単に起動することが可能です。
Rancher を導入する¶
課題
コンテンツ記載
アプリケーションをデプロイ¶
課題
コンテンツ記載
インフラの可用性を向上させる¶
k8s Master の冗長化¶
API受付をするマスタ系のノードやetcdやkubernetesサービスの高可用性も担保しましょう。
また、障害設計をどの単位(DC単位、リージョン単位)で行うかも検討をしましょう。
ログの確認、デバッグ方法¶
標準のkubectlだとログがおいづらいときがあるため以下のツールの検討をします。
- kubernetesホストの/var/log/containerにログは保管。(systemd系の場合)
- sternなどのログ管理ツールを活用する
- fluentdを使いログを集約する。
コンテナクラスタの監視¶
監視する対象として、メトリクス監視、サービス呼び出し、サービスメッシュなど分散環境になったことで従来型のアーキテクチャとは違った監視をする必要があります。 簡単にスケールアウトできる=監視対象が動的というような考え方をします。
また、分散環境では1つのアプリケーションでも複数のサービス呼び出しがおこなわれるため、どのようなサービス呼び出しが行われているかも確認できる必要があります。
- (heapster|Prometheus) + Grafana + InfluxDB を使いコンテナクラスタの監視。
- 分散環境に於けるサービスの呼び出しを可視化 Traces = Zipkin
- ServiceGraph Graphbiz & Prometeus
- ServiceMesh
Helmで提供されているGrafana+Prometheusをデプロイし監視することにチャレンジしてみましょう。 完成図としては以下のようなイメージです。
セキュリティアップグレード¶
例えば、脆弱性があった場合の対処方法はどうすればよいか。
- ノードごとにバージョンアップするため、ある程度の余力を見込んだ設計とする。
- kubectl drain を使いノードで動いているPodを別ノードで起動、対象ノードをアップデートし、ポッドを戻す。
DRをどうするか?¶
アプリケーションのポータビリティはコンテナで実現。 別クラスタで作成されたPVはそのままは参照できないので以下の方法を検討する。
- CSI (Container Storage Interface)の既存ボリュームのインポートに対応をまつ
- Heptio ark: https://github.com/heptio/ark + SVM-DR
Podが停止した場合のアプリケーションの動作¶
Dynamic ProvisioningされたPVCのPod障害時の動作については以下のような動作になります。 PVCはTridentを使ってデプロイしたものです。
- 停止したPodは別ノードで立ち上がる
- Podからマウントしていたボリュームは再度別ノードでもマウントされデータの読み書きは継続可能
Stateful Set
を使い、MongoDBを複数ノードで構成し上記の検証を行った結果が以下のリンク先で確認できます。
このチャプターはドラフト段階です。
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
を実行する動きをします。非常に便利なものになります。
取得できた情報を元に対応実施
- マニフェストファイルの修正
オペレーション簡易化のためデフォルトストレージクラスを設定¶
サンプルで公開されているマニフェストを試したいときに以下の設定をしておくと簡単に起動できるようになります。
- デフォルトのストレージクラスを設定
- external ip が付与できるようにするような仕組みを導入する
kubectl patch storageclass [StorageClass名] -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
このドキュメントは整備中です。
用語集¶
本ラボで出てくる単語集です。
おもに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 Monitoring¶
Kubernetes configuration¶
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)¶
- Ingress https://github.com/nginxinc/kubernetes-ingress/tree/master/examples
- MetalLB https://metallb.universe.tf/
- Trafik
- istio https://istio.io/
Kubernetes Security¶
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をデプロイするネームスペースを作成します。
以下のコマンドでネームスペースを作成します。
$ 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を作成するサンプルです。
上記のマニフェストファイルをインプットとして、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>
1つのエンドポイントから複数のサービス呼びだしを実現することができるようになりました。
DNS登録実施¶
Ingress経由でアクセスするにはホスト名を使用してアクセスします。 本ラボではDNSサーバを共通で準備しています。
Aレコードのエントリは以下のようなスクリプトを準備することで各ユーザが自身で登録することが可能なしくみです。
#!/bin/bash
ETCD="http://192.168.1.1:2379,http://192.168.1.2:2379,http://192.168.1.3:2379"
ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints $ETCD "$@"
以下のようにしてDNSに登録可能です(jenkins.user1x.ndxlab.net で 192.168.1x.10 を登録します)
$ etcdctl put /dns/net/ndxlab/user1X/jenkins '{"host":"192.168.1x.10"}'
名前解決ができているか確認します。
$ nslookup app-name.user1X.ndxlab.net
やるべきこと一覧¶
このドキュメント全体のTODOをまとめたもの
ToDos¶
課題
コンテンツ記載
(元のエントリ は、 Level4/rancher/index.rst の 15 行目です)
課題
コンテンツ記載
(元のエントリ は、 Level4/rancher/index.rst の 20 行目です)
課題
コンテンツ記載
(元のエントリ は、 /home/docs/checkouts/readthedocs.org/user_builds/datatechnologylab/checkouts/stable/docs/source/Level4/rancher/index.rst の 15 行目です)
課題
コンテンツ記載
(元のエントリ は、 /home/docs/checkouts/readthedocs.org/user_builds/datatechnologylab/checkouts/stable/docs/source/Level4/rancher/index.rst の 20 行目です)
DesignDoc¶
Design: kubernetes クラスタの設計要素について¶
ラボ環境を作成する際に検討したことやなぜそのようなジャッジをしたかのメモを残す場所
ネットワーク設計¶
マルチクラスタ構成時のネットワーク構成について マルチテナントはどうする?
ストレージ設計¶
管理ポートのネットワークはどうするか?
アーキテクチャとして、cluster管理 LIF を公開するか?それともSVM管理LIFか?
- マルチテナントを構成するのであれば k8s クラスタ単位にSVMを割り当てるデザインとする。マネジメントもSVMをユーザに渡す。
StorageClass までを管理者側で作成
PersistentVolumeClaim は開発者が作成するが、ある程度のパターンはカタログ化して提供する。
無制限に作られてしまうと困るので、k8s 側で Storage Quota を設定、Namespace 毎に指定。ストレージ側では設定なし。 https://kubernetes.io/docs/concepts/policy/resource-quotas/