はじめに
今回は、ステートフルセット、イングレス辺りをやってみます。
関連記事
コンテナ型仮想化技術 Study01 / Docker基礎
コンテナ型仮想化技術 Study02 / Docker レジストリ
コンテナ型仮想化技術 Study03 / Docker Compose
コンテナ型仮想化技術 Study04 / Minikube & kubectl簡易操作
コンテナ型仮想化技術 Study05 / Pod操作
コンテナ型仮想化技術 Study06 / ReplicaSet, Deployment, Service
コンテナ型仮想化技術 Study06' / Kubernetesネットワーク問題判別
コンテナ型仮想化技術 Study07 / ストレージ
コンテナ型仮想化技術 Study08 / Statefulset, Ingress
コンテナ型仮想化技術 Study09 / Helm
参考情報
レプリカを持つステートフルアプリケーションを実行する
Exposing TCP and UDP Services via ingress on Minikube
Accessing Kubernetes Pods from Outside of the Cluster
NGINX Ingress Controller - Exposing TCP and UDP services
ステートフルセットの操作
ステートフルセットはデプロイメントと似たリソースで複数Podの管理を行うことができますが、ステートフルという名前の通り、各Podの"ステート"を維持するための仕組みが組み込まれたリソースです。デプロイメントと違い、個々のPodはIDにより識別され、それぞれ専用の永続ボリュームがアサインされることになります。
Minikube環境で、以下のチュートリアルをやってみます。
レプリカを持つステートフルアプリケーションを実行する
ただ、このチュートリアルで提供されているマニフェストファイルのパラメータ値は、mysqlというネーミングがいたるところに出てきて、実際のところどの値とどの値を合わせないといけないかが分かりにくい。
ネーミング変更や余分と思われる箇所を削除するなど、若干カスタマイズを行って試してみます。
ConfigMap作成
mysql-configmap.yml適用 (これはそのまま)
vagrant@minikube:~/statefulset$ kubectl apply -f mysql-configmap.yaml
configmap/mysql created
確認
vagrant@minikube:~/statefulset$ kubectl get configmap
NAME DATA AGE
mysql 2 2m47s
vagrant@minikube:~/statefulset$ kubectl get configmap mysql -o yaml
apiVersion: v1
data:
master.cnf: |
# Apply this config only on the master.
[mysqld]
log-bin
slave.cnf: |
# Apply this config only on slaves.
[mysqld]
super-read-only
kind: ConfigMap
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"master.cnf":"# Apply this config only on the master.\n[mysqld]\nlog-bin\n","slave.cnf":"# Apply this config only on slaves.\n[mysqld]\nsuper-read-only\n"},"kind":"ConfigMap","metadata":{"annotations":{},"labels":{"app":"mysql"},"name":"mysql","namespace":"default"}}
creationTimestamp: "2019-12-11T02:04:42Z"
labels:
app: mysql
name: mysql
namespace: default
resourceVersion: "263977"
selfLink: /api/v1/namespaces/default/configmaps/mysql
uid: 6ced75a7-61af-4cbc-a468-149fc606ab08
Service作成
mysql-services.yamlをカスタマイズ
# Headless service for stable DNS entries of StatefulSet members.
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
ports:
- name: mysql-port
port: 3306
type: ClusterIP
clusterIP: None
selector:
app: mysql-sts
---
# Client service for connecting to any MySQL instance for reads.
# For writes, you must instead connect to the master: mysql-0.mysql.
apiVersion: v1
kind: Service
metadata:
name: mysql-read
spec:
ports:
- name: mysql-port
port: 3306
selector:
app: mysql-sts
※2つ目のClusterIPのサービスもここでは使わないので削除しておけばよかった....
適用
vagrant@minikube:~/statefulset$ kubectl apply -f mysql-services.yaml
service/mysql-service created
service/mysql-read created
確認
vagrant@minikube:~/statefulset$ kubectl get service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 41d <none>
mysql-read ClusterIP 10.98.33.98 <none> 3306/TCP 6m51s app=mysql-sts
mysql-service ClusterIP None <none> 3306/TCP 6m51s app=mysql-sts
Statefulset作成
mysql-statefulset.yamlをカスタマイズ
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql-sts
serviceName: mysql-service
replicas: 3
template:
metadata:
labels:
app: mysql-sts
spec:
initContainers:
- name: init-mysql
image: mysql:5.7
command:
- bash
- "-c"
- |
set -ex
# Generate mysql server-id from pod ordinal index.
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
echo [mysqld] > /mnt/conf.d/server-id.cnf
# Add an offset to avoid reserved server-id=0 value.
echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
# Copy appropriate conf.d files from config-map to emptyDir.
if [[ $ordinal -eq 0 ]]; then
cp /mnt/config-map/master.cnf /mnt/conf.d/
else
cp /mnt/config-map/slave.cnf /mnt/conf.d/
fi
volumeMounts:
- name: conf
mountPath: /mnt/conf.d
- name: config-map
mountPath: /mnt/config-map
- name: clone-mysql
image: gcr.io/google-samples/xtrabackup:1.0
command:
- bash
- "-c"
- |
set -ex
# Skip the clone if data already exists.
[[ -d /var/lib/mysql/mysql ]] && exit 0
# Skip the clone on master (ordinal index 0).
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
[[ $ordinal -eq 0 ]] && exit 0
# Clone data from previous peer.
ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
# Prepare the backup.
xtrabackup --prepare --target-dir=/var/lib/mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
containers:
- name: mysql-container
image: mysql:5.7
env:
- name: MYSQL_ALLOW_EMPTY_PASSWORD
value: "1"
ports:
- name: mysql-port
containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 500m
memory: 1Gi
livenessProbe:
exec:
command: ["mysqladmin", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
# Check we can execute queries over TCP (skip-networking is off).
command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 1
- name: xtrabackup
image: gcr.io/google-samples/xtrabackup:1.0
ports:
- name: xtrabackup
containerPort: 3307
command:
- bash
- "-c"
- |
set -ex
cd /var/lib/mysql
# Determine binlog position of cloned data, if any.
if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
# XtraBackup already generated a partial "CHANGE MASTER TO" query
# because we're cloning from an existing slave. (Need to remove the tailing semicolon!)
cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
# Ignore xtrabackup_binlog_info in this case (it's useless).
rm -f xtrabackup_slave_info xtrabackup_binlog_info
elif [[ -f xtrabackup_binlog_info ]]; then
# We're cloning directly from master. Parse binlog position.
[[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
rm -f xtrabackup_binlog_info xtrabackup_slave_info
echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
fi
# Check if we need to complete a clone by starting replication.
if [[ -f change_master_to.sql.in ]]; then
echo "Waiting for mysqld to be ready (accepting connections)"
until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done
echo "Initializing replication from clone position"
mysql -h 127.0.0.1 \
-e "$(<change_master_to.sql.in), \
MASTER_HOST='mysql-0.mysql', \
MASTER_USER='root', \
MASTER_PASSWORD='', \
MASTER_CONNECT_RETRY=10; \
START SLAVE;" || exit 1
# In case of container restart, attempt this at-most-once.
mv change_master_to.sql.in change_master_to.sql.orig
fi
# Start a server to send backups when requested by peers.
exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
"xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 100m
memory: 100Mi
volumes:
- name: conf
emptyDir: {}
- name: config-map
configMap:
name: mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
※Statefulset自体のLabel指定をはずす、Pod TemplateのLabel名、コンテナーの名前、ポートの名前辺りを変更しています。
適用
vagrant@minikube:~/statefulset$ kubectl apply -f mysql-statefulset.yaml
statefulset.apps/mysql created
確認
vagrant@minikube:~/statefulset$ kubectl get service,pod,storageclass,pvc,pv -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 41d <none>
service/mysql-read ClusterIP 10.98.33.98 <none> 3306/TCP 10m app=mysql-sts
service/mysql-service ClusterIP None <none> 3306/TCP 10m app=mysql-sts
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/mysql-0 2/2 Running 0 9m44s 172.17.0.10 minikube <none> <none>
pod/mysql-1 2/2 Running 0 9m36s 172.17.0.11 minikube <none> <none>
pod/mysql-2 2/2 Running 0 9m28s 172.17.0.12 minikube <none> <none>
NAME PROVISIONER AGE
storageclass.storage.k8s.io/standard (default) k8s.io/minikube-hostpath 41d
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
persistentvolumeclaim/data-mysql-0 Bound pvc-4570a5b6-6e12-48da-bb16-b9524e0a9dfd 10Gi RWO standard 3h35m Filesystem
persistentvolumeclaim/data-mysql-1 Bound pvc-b2fdc30d-ea7a-4b2b-9f07-016db25f03aa 10Gi RWO standard 3h35m Filesystem
persistentvolumeclaim/data-mysql-2 Bound pvc-c991093e-96b5-4844-9ed9-897824b3c029 10Gi RWO standard 3h35m Filesystem
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/pvc-4570a5b6-6e12-48da-bb16-b9524e0a9dfd 10Gi RWO Delete Bound default/data-mysql-0 standard 3h35m Filesystem
persistentvolume/pvc-b2fdc30d-ea7a-4b2b-9f07-016db25f03aa 10Gi RWO Delete Bound default/data-mysql-1 standard 3h35m Filesystem
persistentvolume/pvc-c991093e-96b5-4844-9ed9-897824b3c029 10Gi RWO Delete Bound default/data-mysql-2 standard 3h35m Filesystem
mysql-0,1,2というPodが3つ起動しました!それぞれ、172.17.0.10, 172.17.0.11, 172.17.0.12 というIPアドレスが割り当てられています。
さて、busyboxのpod作成して、名前解決を試してみます。
vagrant@minikube:~$ kubectl run -it busybox --restart=Never --rm --image=busybox sh
If you don't see a command prompt, try pressing enter.
/ # ping -c 3 mysql-service
PING mysql-service (172.17.0.11): 56 data bytes
64 bytes from 172.17.0.11: seq=0 ttl=64 time=0.366 ms
64 bytes from 172.17.0.11: seq=1 ttl=64 time=0.122 ms
64 bytes from 172.17.0.11: seq=2 ttl=64 time=0.049 ms
--- mysql-service ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.049/0.179/0.366 ms
/ # ping -c 3 mysql-service
PING mysql-service (172.17.0.10): 56 data bytes
64 bytes from 172.17.0.10: seq=0 ttl=64 time=0.049 ms
64 bytes from 172.17.0.10: seq=1 ttl=64 time=0.051 ms
64 bytes from 172.17.0.10: seq=2 ttl=64 time=0.054 ms
--- mysql-service ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.049/0.051/0.054 ms
/ # ping -c 3 mysql-service
PING mysql-service (172.17.0.12): 56 data bytes
64 bytes from 172.17.0.12: seq=0 ttl=64 time=0.040 ms
64 bytes from 172.17.0.12: seq=1 ttl=64 time=0.042 ms
64 bytes from 172.17.0.12: seq=2 ttl=64 time=0.080 ms
--- mysql-service ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.040/0.054/0.080 ms
mysql-serviceにpingを打ってみると、その都度ランダムにmysql-xのアドレスにアクセスしているのが分かります。
補足
各リソースの関連図
上で出来上がった各リソースの関連を図示してみると、こんなイメージでしょうか。
ステートフルセットでは、PodやVolumeが動的に作成されますが、各Podには固有の名前が付けられてVolumeもそれぞれのPod専用に割り当てられます。また、ステートフルセットを作成する際はHeadlessのサービス(clusterIP: Noneを指定したサービス)と関連付ける必要があります。
この例では、Headlessサービス以外に、もう一つClusterIPのサービスを定義しています。
また、上で使用したmysql-statefulset.yamlではvolumeClaimTemplates.spec.storageClassNameを明示指定していませんが、その場合、デフォルトのStorageClassが使われます。minikube環境の場合standardというStorageClassがデフォルトとして定義されており、ここから動的にVolumeがプロビジョニングされることになります。
vagrant@minikube:~/statefulset$ kubectl get storageclass
NAME PROVISIONER AGE
standard (default) k8s.io/minikube-hostpath 41d
vagrant@minikube:~/statefulset$ kubectl describe storageclass standard
Name: standard
IsDefaultClass: Yes
Annotations: storageclass.kubernetes.io/is-default-class=true
Provisioner: k8s.io/minikube-hostpath
Parameters: <none>
AllowVolumeExpansion: <unset>
MountOptions: <none>
ReclaimPolicy: Delete
VolumeBindingMode: Immediate
Events: <none>
Serviceについての整理
DeploymentやStatefulsetなど、複数Podへのアクセスを考えた場合、手前にServiceを配置してそれを利用してアクセスすることになると思われますが、ClusterIP, NodePort, Headless辺り混乱してきたので理解を一旦整理します。
参考: コンセプト - Service
ClusterIP
ClusterIPのServiceを定義すると、代表IPアドレスが動的にアサインされて、サービスの名前でIPアドレスが解決できるよう内部DNSに登録される。
サービスの定義では、ターゲットのPodがListenしているポート番号と、公開用のポート番号の組を指定する(複数ポート指定可)。上の例だと、クライアントとなるPodからは、my-service:80にアクセスすると、ターゲットのPodの9376ポートにリクエストが割り振られることになる。
ClusterIPはk8s Cluster内で利用できるものなので、クラスター内のPodから利用することが前提(外部からのアクセスは不可)。
type指定を省略した場合デフォルトでClusterIPと認識される。
NodePort
NodePortのServiceを定義すると、各ノードのIPアドレス上の特定のポートを外部に公開することができる。
「nodePort: 30000」というように公開用のポートを明示指定しなければ、30000-32767の範囲で使用されていないポートが動的に割り当てられる。
k8s Cluster外のクライアントから、<各ノードのIP>:<公開用ポート番号>でアクセス可能。
各ノードで受け付けられたリクエストはkube-proxyによりMyAppのPodに負荷分散される(受け付けたノード以外のノードのPodにも分散される)。
※Podへのルーティングを行うために前述のClusterIPが内部的に作成される。
Statefulset と Headless Service
Serviceの定義で"type: ClusterIP"、および、"clusterIP: None"を指定するとHeadless Serviceとして認識される。代表IPアドレスの付与や負荷分散は行われない。
サービス名で名前解決すると、各ターゲットのPodのアドレスがランダムに返される。
k8s Cluster内のクライアントとなるPodからは、my-service:3306で、ターゲットのいずれかのPodにアクセスすることになる。
Statefulsetを作成する場合、Headless Serviceの定義は必須。
StatefulSets currently require a Headless Service to be responsible for the network identity of the Pods. You are responsible for creating this Service.
MySQLクライアントからの操作
MySQLクライアントのコンテナが稼働するPodを一時的に立ち上げて、上で作成したSQLサーバーにアクセスしてみます。
vagrant@minikube:~$ kubectl run mysql-client --image=mysql:5.7 -it --rm --restart=Never bash
If you don't see a command prompt, try pressing enter.
root@mysql-client:/# mysql -h mysql-service -e 'SELECT @@server_id,NOW()'
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 100 | 2019-12-11 08:17:07 |
+-------------+---------------------+
root@mysql-client:/# mysql -h mysql-service -e 'SELECT @@server_id,NOW()'
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 102 | 2019-12-11 08:17:18 |
+-------------+---------------------+
root@mysql-client:/# mysql -h mysql-service -e 'SELECT @@server_id,NOW()'
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 101 | 2019-12-11 08:17:19 |
+-------------+---------------------+
MySQLのクライアントからmysqlコマンドで"mysql-service"というホスト名のMySQLサーバーにアクセスしてサーバーの情報を取得していますが、同じホスト名を指定してもサーバーIDが異なるものが返される、つまり、その都度別のPodのMySQLサーバーにアクセスしている様子が確認できます。
イングレスの操作(non-HTTP/HTTPS)
Ingressは、Kubernetesクラスタにデプロイされたサービスを、クラスタの外部へ公開するためのリソースです。
TCP/IPベースの通信であれば、Ingressを用いて外部にサービスを公開できると思われますが、ほとんどのドキュメントが、HTTP/HTTPSの通信を前提に記述されているようです。恐らく、Kubernetesで管理するアプリケーションとしては、主としてWebアプリケーションやRESTfulなサービスを想定しているからだと思われます。
公式ドキュメントでも以下のような記述となっています。
What is Ingress?
Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource.
また、Ingressの実体としてIngress Controllerという実装が必要になりますが、nginxを利用したNGINX Ingress ControllerというものがOSSとして無料で提供されており、HTTP/HTTPSの公開はこれを利用することで実現できるようです。
ただ、訳あってHTTP/HTTPS以外の通信を扱いたいので(ゆくゆくは独自プロトコルを使用したミドルウェアをKubernetes環境で動かしたいので)、TCP/UDPの通信の公開方法を探ります。
ここでは、上でステートフルセットとして作成したMySQLのサービスを外部公開してKubernetesクラスター外のMySQLクライアントからKubernetes上のMySQLサーバーにアクセスする、というのを目指します。
ということで色々調べていると、ドンピシャで以下のような記事がありました!
Exposing TCP and UDP Services via ingress on Minikube
先達あらまほしき事なり。
これをベースに進めます。
その他、参考
Accessing Kubernetes Pods from Outside of the Cluster
NGINX Ingress Controller - Exposing TCP and UDP services
全体像
※今回は、minikube環境で1ノード構成上で簡易的に試すために、NGINX Ingress Controller実装のPodの設定でhostNetwork:trueにすることで、このノードのアドレス上にポートを公開するようにしていますが、実際のKubernetesクラスター環境では、当然このPodがどのノードで動くか分からないし、シングルポイントにならないように構成しないといけません。
NGINX Ingress Controller - Exposing TCP and UDP servicesにあるように、LoadBlancerタイプのService作って公開する、といったようなことを考える必要があると思われます。
K8s Cluster側
NGINX Ingress Controller準備
Ingress Controller実装のマニフェストファイルを入手 (Deploymentとして実装されているっぽい)。
https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
vagrant@minikube:~/ingress$ wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
--2019-12-11 10:07:24-- https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.196.133
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.196.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6364 (6.2K) [text/plain]
Saving to: ‘mandatory.yaml’
mandatory.yaml 100%[===========================================================================================================================================>] 6.21K --.-KB/s in 0s
2019-12-11 10:07:25 (104 MB/s) - ‘mandatory.yaml’ saved [6364/6364]
hostNetwork: true
を追記します。
...
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
# wait up to five minutes for the drain of connections
terminationGracePeriodSeconds: 300
serviceAccountName: nginx-ingress-serviceaccount
nodeSelector:
kubernetes.io/os: linux
hostNetwork: true
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
...
適用します。
vagrant@minikube:~/ingress$ kubectl apply -f mandatory.yaml
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
確認
vagrant@minikube:~/ingress$ kubectl get all -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-ingress-controller-5bbd46cd86-pk4ft 1/1 Running 0 79s 10.0.2.15 minikube <none> <none>
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/nginx-ingress-controller 1/1 1 1 79s nginx-ingress-controller quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1 app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/part-of=ingress-nginx
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/nginx-ingress-controller-5bbd46cd86 1 1 1 79s nginx-ingress-controller quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1 app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/part-of=ingress-nginx,pod-template-hash=5bbd46cd86
MySQL用ポート公開用ConfigMap
マニフェストファイル作成
apiVersion: v1
kind: ConfigMap
metadata:
name: tcp-services
namespace: ingress-nginx
data:
3306: "default/mysql-service:3306"
適用
vagrant@minikube:~/ingress$ kubectl apply -f configmap-tcp-services.yaml
configmap/tcp-services configured
確認
vagrant@minikube:~/ingress$ netstat -an | grep 3306
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
tcp6 0 0 :::3306 :::* LISTEN
minikubeのノード上でnetstat見ると、3306ポートがListenされました!!!
MySQLクライアント側
別のノードにMySQLクライアント環境を作ってアクセスしてみます。NFSサーバー用に用意したVirtualBox上のノード使うことにします。
Ubuntu上にDockerCEインストール
以下のガイドに従ってDockerCEインストール
https://docs.docker.com/install/linux/docker-ce/ubuntu/
以下のコマンド順番に実行
vagrant@nfsserver:~$ sudo apt-get update
vagrant@nfsserver:~$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
vagrant@nfsserver:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
vagrant@nfsserver:~$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
vagrant@nfsserver:~$ sudo apt-get update
vagrant@nfsserver:~$ sudo apt-get install docker-ce docker-ce-cli containerd.io
バージョン確認
vagrant@nfsserver:~$ docker version
Client: Docker Engine - Community
Version: 19.03.5
API version: 1.40
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:50:12 2019
OS/Arch: linux/amd64
Experimental: false
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/version: dial unix /var/run/docker.sock: connect: permission denied
MySQLクライアント用コンテナ実行
実行!(クライアントと言いつつサーバー上げちゃってますが、これのクライアントコマンドを使います。)
vagrant@nfsserver:~$ sudo docker container run -it --rm -e MYSQL_ROOT_PASSWORD=password mysql:5.7
確認
vagrant@nfsserver:~$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0523e710e118 mysql:5.7 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp, 33060/tcp zealous_galileo
コンテナに接続してbashからMySQLサーバーにアクセスしてみます。
が、pingコマンド入ってなかったのでまずインストール
vagrant@nfsserver:~$ sudo docker exec -it 0523e710e118 bash
root@0523e710e118:/# apt-get update
...
root@0523e710e118:/# apt-get install iputils-ping net-tools
...
一応minikubeのノードのIPアドレスにpingが通るのを確認。
root@0523e710e118:/# ping -c 3 172.16.10.10
PING 172.16.10.10 (172.16.10.10) 56(84) bytes of data.
64 bytes from 172.16.10.10: icmp_seq=1 ttl=62 time=0.705 ms
64 bytes from 172.16.10.10: icmp_seq=2 ttl=62 time=0.785 ms
64 bytes from 172.16.10.10: icmp_seq=3 ttl=62 time=0.836 ms
--- 172.16.10.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.705/0.775/0.836/0.058 ms
では、いよいよMySQLサーバーにアクセス。
root@0523e710e118:/# mysql -h 172.16.10.10 -e 'SELECT @@server_id,NOW()'
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 102 | 2019-12-11 11:39:33 |
+-------------+---------------------+
root@0523e710e118:/# mysql -h 172.16.10.10 -e 'SELECT @@server_id,NOW()'
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 101 | 2019-12-11 11:39:36 |
+-------------+---------------------+
root@0523e710e118:/# mysql -h 172.16.10.10 -e 'SELECT @@server_id,NOW()'
+-------------+---------------------+
| @@server_id | NOW() |
+-------------+---------------------+
| 100 | 2019-12-11 11:39:39 |
+-------------+---------------------+
来ました!きちんと、リクエスト毎に違うサーバー(Pod)にアクセスしているのが確認できました!