はじめに
「Docker/Kubernetes 実践コンテナ開発入門」を読みながらKubernetesを勉強していたのですが、コンテナ技術の発展が早く、出版が2018年8月ということで内容が少し古くなってきました。特に7章3節のHelmの解説では、Helmのバージョンがv31に上がったことによるコマンド変更があり、Helm v3を使用する場合には手順がそのまま使えなくなっています。この記事ではHelm v3を使用した場合の手順について解説します。
前提
- 「Docker/Kubernetes 実践コンテナ開発入門」を購入し、読んでいる方向けです。
- あくまで差分の紹介なので、技術の解説等は本を読んでください。
環境
- mac OS Catalina 10.15.5
- プロセッサ: 2.3 GHz デュアルコアIntel Core i5
- メモリ: 8 GB 2133 MHz LPDDR3
dockerはdocker for macを使用してローカルで実行しました。
$ docker --version
Docker version 19.03.8, build afacb8b
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.4", GitCommit:"c96aede7b5205121079932896c4ad89bb93260af", GitTreeState:"clean", BuildDate:"2020-06-18T02:59:13Z", GoVersion:"go1.14.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.6-beta.0", GitCommit:"e7f962ba86f4ce7033828210ca3556393c377bcc", GitTreeState:"clean", BuildDate:"2020-01-15T08:18:29Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}
また、VS Codeでyamlを編集していたのですが、自動整形をした際の中括弧の挙動がおかしかったので、VS Code拡張機能のvscode-helm
をインストールしました。
手順
Helmのセットアップ
kubectlをローカルkubernetesクラスタに切り替えておきます。
HomebrewでHelmをインストールします。
$ brew install helm
$ helm version
version.BuildInfo{Version:"v3.2.4", GitCommit:"0ad800ef43d3b826f31a5ad8dfbb4fe05d143688", GitTreeState:"dirty", GoVersion:"go1.14.3"}
v3でTillerサーバが廃止されたので、helm init
は不要です。
v2ではkubernetesクラスタ上にTillerサーバがデプロイされ、クライアントのhelmコマンドでTillerサーバのAPIを呼び出し、命令を受けたTillerサーバがkubernetesクラスタのAPIを呼び出すという流れになっていました。拡張性のある構成だとは思いますが、Tillerサーバ周りのサービス・アカウントの設定が複雑になるということで使い勝手が悪かったようです。v3 ではTillerサーバが廃止され、クライアントから直接kubernetesクラスタのAPIを呼び出すようになりました。マニフェストの生成もクライアントで行われるようになっています。詳細は下記のサイトをご覧ください。
Helmの概念
v2とは違いstableリポジトリはデフォルトでは利用できなくなっています。次のようにすればstableリポジトリを追加できます。
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
stableリポジトリは将来廃止される予定で、分散型のリポジトリに移行するようです。
The stable repository is no longer added by default. This repository will be deprecated during the life of Helm v3 and we are now moving to a distributed model of repositories that can be searched by the Helm Hub.
Ref: https://helm.sh/blog/helm-v3-beta/
リポジトリの検索はhelm search
で行いますが、repo
とhub
の2つで検索を指定します。hubの検索は一部のリポジトリのみが表示されます。そのリポジトリからChartを使用するには、関連するリポジトリをHelmリポジトリリストに追加する必要があります。
$ helm search -h
Search provides the ability to search for Helm charts in the various places
they can be stored including the Helm Hub and repositories you have added. Use
search subcommands to search different locations for charts.
Usage:
helm search [command]
Available Commands:
hub search for charts in the Helm Hub or an instance of Monocular
repo search repositories for a keyword in charts
Flags:
...
Chartをインストールする
redmineをインストールします。bitnami
リポジトリを追加します。一応リポジトリの情報を最新化しておきます。
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm repo update
インストールするChartの情報です。
$ helm show chart bitnami/redmine
helm show chart bitnami/redmine
apiVersion: v1
appVersion: 4.1.1
dependencies:
- condition: mariadb.enabled
name: mariadb
repository: https://charts.bitnami.com/bitnami
version: 7.x.x
- condition: postgresql.enabled
name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 8.x.x
description: A flexible project management web application.
home: http://www.redmine.org/
icon: https://bitnami.com/assets/stacks/redmine/img/redmine-stack-220x234.png
keywords:
- redmine
- project management
- www
- http
- web
- application
- ruby
- rails
maintainers:
- email: containers@bitnami.com
name: Bitnami
name: redmine
sources:
- https://github.com/bitnami/bitnami-docker-redmine
version: 14.2.4
インストールします。パラメータをredmine.yaml
で定義します。
redmineUsername: abeT
redminePassword: abeT
redmineLanguage: ja
service:
type: NodePort
リリース名は--name
で指定せず、helm install
の直後に指定します。
$ helm install -f redmine.yaml redmine bitnami/redmine
NAME: redmine
LAST DEPLOYED: Fri Jun 26 15:42:19 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the Redmine URL:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services redmine)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo "Redmine URL: http://$NODE_IP:$NODE_PORT/"
2. Login with the following credentials
echo Username: abeT
echo Password: $(kubectl get secret --namespace default redmine -o jsonpath="{.data.redmine-password}" | base64 --decode)
インストールされたものの一覧を表示します。
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
redmine default 1 2020-06-26 13:55:26.228257 +0900 JST deployed redmine-14.2.4 4.1.1
作成されたリソースを確認します。
$ kubectl get service,deployment
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24m
service/redmine NodePort 10.97.203.207 <none> 80:30677/TCP 114s
service/redmine-mariadb ClusterIP 10.110.204.194 <none> 3306/TCP 114s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/redmine 1/1 1 1 114s
service/redmine
がNodePort
になっており、http://localhost:30677
でredmineにアクセスできるようになっています。
※ deployment.apps/redmineがREADYにならず、止まってしまう事象が発生しました。原因は不明ですが(多分メモリの不足?)、Reset Kubernetes Cluster
でクラスターを全削除してから実行するとうまくいく場合があります。
アンインストール
次のコマンドでアンインストールを実行できます。v3ではデフォルトではリビジョンの記録が残りません。--keep-history
を付与することで、リビジョンを残しておくことができます。
$ helm uninstall redmine --keep-history
release "redmine" uninstalled
リビジョンを確認できます。
$ helm ls --all
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
redmine default 1 2020-06-26 16:14:29.972481 +0900 JST uninstalled redmine-14.2.4 4.1.1
ロールバックを実行します。
$ helm rollback redmine 1
Rollback was a success! Happy Helming!
削除がロールバックされて、実行状態になっています。
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
redmine default 2 2020-06-29 14:21:46.552373 +0900 JST deployed redmine-14.2.4 4.1.1
リビジョンの記録を残さないで削除するには--keep-history
なしで削除します。
$ helm uninstall redmine
release "redmine" uninstalled
$ helm ls --all
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
Chartを自作する
Chartのテンプレートを作成します。
$ helm create echo
Creating echo
$ tree .
.
└── echo
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
4 directories, 10 files
Macには標準でtree
コマンドは入っていないので、Homebrewでインストールしました。
$ brew install tree
v2と比べると、次の3つファイルが増えています。これらのファイルは今回は使用しません。
- hpa.yaml # HorizontalPodAutoscalerのマニフェスト
- serviceaccount.yaml # ServiceAccountのマニフェスト
- test-connection.yaml # Chartをテストするのに使用する
Chartのテンプレートの構成はこちらを参照してください。
生成されたdeployment.yaml
の中身は次のようになっています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "echo.fullname" . }}
labels:
{{- include "echo.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "echo.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "echo.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "echo.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
あらかじめ様々なパラメータが抽象化されています。開発者が編集するのはspec.template.spec
の部分です。次のように変更します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "echo.fullname" . }}
labels:
app: {{ include "echo.name" . }}
chart: {{ include "echo.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "echo.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "echo.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "echo.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: nginx
image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}"
imagePullPolicy: {{ .Values.nginx.image.pullPolicy }}
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
path: {{ .Values.nginx.healthCheck }}
port: http
readinessProbe:
httpGet:
path: {{ .Values.nginx.healthCheck }}
port: http
env:
- name: BACKEND_HOST
value: {{ .Values.nginx.backendHost | quote }}
- name: echo
image: "{{ .Values.echo.image.repository }}:{{ .Values.echo.image.tag }}"
imagePullPolicy: {{ .Values.echo.image.pullPolicy }}
ports:
- containerPort: {{ .Values.echo.httpPort }}
env:
- name: HTTP_PORT
value: {{ .Values.echo.httpPort | quote }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
パラメータはvalues.yaml
で指定します。生成されたvalues.yaml
の中身は次のようになっています。
# Default values for echo.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
これを次のように書き換えます。
replicaCount: 1
nginx:
image:
repository: gihyodocker/nginx
pullPolicy: Always
tag: latest
healthCheck: /
backendHost: localhost:8080
echo:
image:
repository: gihyodocker/echo
pullPolicy: Always
tag: latest
httpPort: 8080
Serviceも同様に書き換えます。生成されたServiceの中身は次のようになっています。
apiVersion: v1
kind: Service
metadata:
name: {{ include "echo.fullname" . }}
labels:
{{- include "echo.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "echo.selectorLabels" . | nindent 4 }}
これを次のようにします。
apiVersion: v1
kind: Service
metadata:
name: {{ include "echo.fullname" . }}
labels:
app: {{ include "echo.name" . }}
chart: {{ include "echo.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: {{ .Values.service.name }}
selector: {{- include "echo.selectorLabels" . | nindent 4 }}
values.yaml
に次の設定を追記します。
service:
name: nginx
type: ClusterIP
port: 80
次はIngressです。生成されたIngressの中身は次のようになっています。
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "echo.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "echo.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
backend:
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
metadata.labels
を書き換えます。
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "echo.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ include "echo.name" . }}
chart: {{ include "echo.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
backend:
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
values.yaml
に次の設定を追記します。これはvalues.yaml
生成時のデフォルトの値です。
ingress:
enabled: false
annotations:
{}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
また、ServiceAccountは今回作成しないので、serviceAccount.create
はfalse
とします。
serviceAccount:
# Specifies whether a service account should be created
create: false
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
values.yaml
全体は次のようになります。
replicaCount: 1
nginx:
image:
repository: gihyodocker/nginx
pullPolicy: Always
tag: latest
healthCheck: /
backendHost: localhost:8080
echo:
image:
repository: gihyodocker/echo
pullPolicy: Always
tag: latest
httpPort: 8080
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: false
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext:
{}
# fsGroup: 2000
securityContext:
{}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
name: nginx
type: ClusterIP
port: 80
ingress:
enabled: false
annotations:
{}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources:
{}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
Chart.yaml
にパッケージングに必要な情報を記載します。
apiVersion: v2
name: echo
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: 0.1.0
helm lint
で文法チェックができます。
$ helm lint echo
==> Linting echo
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
Chartをインストールする
作成したChartをインストールします。helm install --debug --dry-run リリース名 Chart名
コマンドでインストールのdry runを実行できます。dry runでは生成されたマニフェストを確認することができます。
$ helm install --debug --dry-run echo echo
install.go:159: [debug] Original chart version: ""
install.go:176: [debug] CHART PATH: /hogehoge/echo
NAME: echo
LAST DEPLOYED: Mon Jun 29 16:58:44 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
affinity: {}
autoscaling:
enabled: false
maxReplicas: 100
minReplicas: 1
targetCPUUtilizationPercentage: 80
echo:
httpPort: 8080
image:
pullPolicy: Always
repository: gihyodocker/echo
tag: latest
fullnameOverride: ""
imagePullSecrets: []
ingress:
annotations: {}
enabled: false
hosts:
- host: chart-example.local
paths: []
tls: []
nameOverride: ""
nginx:
backendHost: localhost:8080
healthCheck: /
image:
pullPolicy: Always
repository: gihyodocker/nginx
tag: latest
nodeSelector: {}
podAnnotations: {}
podSecurityContext: {}
replicaCount: 1
resources: {}
securityContext: {}
service:
name: nginx
port: 80
type: ClusterIP
serviceAccount:
annotations: {}
create: false
name: ""
tolerations: []
HOOKS:
---
# Source: echo/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "echo-test-connection"
labels:
helm.sh/chart: echo-0.1.0
app.kubernetes.io/name: echo
app.kubernetes.io/instance: echo
app.kubernetes.io/version: "0.1.0"
app.kubernetes.io/managed-by: Helm
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['echo:80']
restartPolicy: Never
MANIFEST:
---
# Source: echo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: echo
labels:
app: echo
chart: echo-0.1.0
release: echo
heritage: Helm
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: nginx
selector:
app.kubernetes.io/name: echo
app.kubernetes.io/instance: echo
---
# Source: echo/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo
labels:
app: echo
chart: echo-0.1.0
release: echo
heritage: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: echo
app.kubernetes.io/instance: echo
template:
metadata:
labels:
app.kubernetes.io/name: echo
app.kubernetes.io/instance: echo
spec:
serviceAccountName: default
securityContext:
{}
containers:
- name: nginx
image: "gihyodocker/nginx:latest"
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
env:
- name: BACKEND_HOST
value: "localhost:8080"
- name: echo
image: "gihyodocker/echo:latest"
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: HTTP_PORT
value: "8080"
resources:
{}
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=echo,app.kubernetes.io/instance=echo" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:80
dry runでパラメータに問題ないか確認できたらインストールします。
$ helm install echo echo
NAME: echo
LAST DEPLOYED: Mon Jun 29 16:59:48 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=echo,app.kubernetes.io/instance=echo" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME 8080:80
アプリが立ち上がっていることがわかります。
$ helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
echo default 1 2020-06-29 16:59:48.534198 +0900 JST deployed echo-0.1.0 0.1.0
$ kubectl get deployment,service,ingress --selector app=echo
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/echo 1/1 1 1 2m10s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/echo ClusterIP 10.111.40.236 <none> 80/TCP 2m10s
Ingressの使用がfalseになっていたので、これをtrueにして実行してみます。デプロイ済みのアプリは削除します。
$ helm uninstall echo
ローカルにはL7ロードバランサがないので、NGINX Ingress Controller
を使用します。インストール方法はこちらを参照してください。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud/deploy.yaml
$ kubectl -n ingress-nginx get service,pod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller LoadBalancer 10.98.29.212 localhost 80:32012/TCP,443:30306/TCP 3m46s
service/ingress-nginx-controller-admission ClusterIP 10.107.104.62 <none> 443/TCP 3m46s
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-6plnl 0/1 Completed 0 3m36s
pod/ingress-nginx-admission-patch-csb5s 0/1 Completed 0 3m36s
pod/ingress-nginx-controller-579fddb54f-d47d7 1/1 Running 0
次に、カスタムValueファイルを作成します。
$ vi echo.yaml
ingress:
enabled: true
hosts:
- host: "ch06-echo.gihyo.local"
paths: ["/"]
カスタムValueファイルを使用してアプリをインストールします。
$ helm install -f echo.yaml echo echo
NAME: echo
LAST DEPLOYED: Mon Jun 29 17:32:19 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
http://ch06-echo.gihyo.local/
curl
でアクセスしてみます。
$ curl http://localhost -H 'Host:ch06-echo.gihyo.local'
Hello Docker!!
これで成功です!
パッケージをつくる
helm package
コマンドでパッケージングできます。
$ helm package echo
$ ls
echo/ echo-0.1.0.tgz echo.yaml
おわりに
今回は「Docker/Kubernetes 実践コンテナ開発入門」をHelm v3で行いました。コンテナまわりの技術は進歩が速くて追いかけるのが大変です。