目的
- ingress を理解する
手段
killercodaで手を動かす
環境
killercoda
securityContext とは
Kubernetesの**Ingress(イングレス)**とは、外部からのHTTPおよびHTTPSリクエストをクラスタ内のサービスにルーティングするためのAPIリソースです。簡単に言うと、**Kubernetesクラスタの「入り口」**のような役割を果たします。
つまり、pod/deployment に対して service リソースを作成して kubernetes クラスター内で公開し、kubernetes クラスターの外部への公開は ingress リソースを作成する必要があるということですね。
代表的な設定は?
ingress
と ingressClass
の二つが存在します。
- ingress : 実際のトラフィックを kubernetes クラスター内部の service へ処理する
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
# 実際の ingress 設定は ingressClass や annotation(rewrite)等が必要になる
# あくまで ingress 設定自身の説明サンプル
- ingressClass : Kubernetesの IngressClass(イングレスクラス) は、どのIngress Controllerが特定のIngressリソースを処理するかを指定するための仕組みです。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx
# この IngressClass は Ingress Controller に ingress-nginx を利用すると宣言
# Ingress Controller は複数(例: NGINX, Traefik, HAProxy)存在するため
次に、deployment 作成 → Pod をクラスター内に公開 → ingress で外部に公開する手順を確認します。
まずは deployment を作成します。
controlplane:~$ k create namespace deployment
# namespace 作成
controlplane:~$ k -n deployment create deployment nginx --image=nginx --replicas=2
# deployment 作成
controlplane:~$ k get -n deployment deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 2/2 2 2 66s
# status 確認
続いて、expose
コマンドで kubernetes クラスター内に公開します。
controlplane:~$ k -n deployment expose deployment nginx --port=80 --dry-run=client -oyaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
namespace: deployment
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
status:
loadBalancer: {}
# nginx という ClusterIP を作成します。
controlplane:~$ k describe -n deployment svc nginx
Name: nginx
Namespace: deployment
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.97.179.26
IPs: 10.97.179.26
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 192.168.0.13:80,192.168.0.14:80 # deployment の EP が二つアサイン
Session Affinity: None
Internal Traffic Policy: Cluster
Events: <none>
controlplane:~$ k get -n deployment svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.97.179.26 <none> 80/TCP 18s
作成した ClusterIP に kubernetes クラスター内部からアクセスします。
controlplane:~$ curl http://10.97.179.26 --head
HTTP/1.1 200 OK
Server: nginx/1.29.1
# controlplane(kubernetes クラスター内部)からアクセスできました。
最後に ingress 設定を作成します。
controlplane:~$ k create ingress -n deployment nginx --rule="example.com/=nginx:80" --dry-run=client -oyaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: nginx
namespace: deployment
spec:
rules:
- host: world.universe.mine
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: Exact
status:
loadBalancer: {}
# --dry-run=client オプションで ingress の yaml を作成します
必要なカラムを追加してきます。
controlplane:~$ cat nginx.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: nginx
namespace: deployment
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # path(ex: /web)にマッチしたアクセスを / に書き換え
spec:
ingressClassName: nginx # どの ingress controller を利用するか指定
rules:
- host: example.com
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: Prefix # Prefix に変更
status:
loadBalancer: {}
この yaml を適用します。
controlplane:~$ k apply -f nginx.yaml
ホスト名でアクセスできるか確認します。
controlplane:~$ curl --head example.com -v
* Host example.com:80 was resolved.
* IPv6: (none)
* IPv4: 10.104.72.18
* Trying 10.104.72.18:80...
* Connected to example.com (10.104.72.18) port 80
> HEAD / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
# 10.104.72.18 は ClusterIP かどうか確認します
controlplane:~$ k get svc -n deployment
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.104.72.18 <none> 80/TCP 7m53s
# ClusterIP に接続できていることが確認できました
ここからは ingress に https を追加します。必要な手順は以下の通りです。
- サーバ証明書を作成
- サーバ証明書を基に
secret
リソース作成 - ingress 設定 yaml に
secret
等の設定を追加
それぞれ順番に実施していきます。
- サーバ証明書を作成
controlplane:~$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.crt -subj="/CN=world.universe.mine/O=world.universe.mine"
.........+..+.........+....+..+.......+.....+...+...+.+...+......+...........+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*........................+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*......+....+........+.............+.........+...+...+..+......+......+...............+.........+.+.....+.............+.....+.......+........+.+..+..........+...+..+.........................+..+...+....+.....+..........+...+..+.............+..+...+...+......................+...+...+..+.........+....+......+........+.+.....+......+......+...+............+...+.........+...+...............+...+.+........+.+............+...+.....+......+.+........+....+............+...+...........+.......+..+.......+........+...+...+............+...+....+...+..+......+.+..............+.+........+................+...........+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.+...+...+.........+.........+....+..+.+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+..+....+...........+......+..........+..+.+......+........+.+.....+......+.+..+......+.........+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+..+...+.............+.....+.......+..+.+...........+....+....................+.+.....+....+..............+.+.........+..+......+..........+...+.....+....+.....+..................+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
controlplane:~$
ingress の https 実装前にどのような証明書が提示されるか確認します。
controlplane:~$ curl -kv https://world.universe.mine:30443/europe
* Host world.universe.mine:30443 was resolved.
* IPv6: (none)
--- snip ---
* ALPN: server accepted h2
* Server certificate:
* subject: O=Acme Co; CN=Kubernetes Ingress Controller Fake Certificate
# `Kubernetes Ingress Controller Fake Certificate` が利用されています
2 .サーバ証明書を基に
secret
リソース作成
controlplane:~$ k create -n world secret tls world-secret --cert=cert.crt --key=cert.key
secret/world-secret created
controlplane:~$ k get -n world secrets world-secret
NAME TYPE DATA AGE
world-secret kubernetes.io/tls 2 11s
controlplane:~$ k describe -n world secrets world-secret
Name: world-secret
Namespace: world
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.key: 1704 bytes
tls.crt: 1220 bytes
controlplane:~$
3 .ingress 設定 yaml に
secret
等の設定を追加
controlplane:~$ k get -n world ingress world -oyaml > world.yaml
controlplane:~$ vi world.yaml
controlplane:~$ cat world.yaml
--- snip ---
spec:
ingressClassName: nginx
tls:
- hosts:
- world.universe.mine
secretName: world-secret
# spec 配下に tls を追加。hosts と証明書の CN は一致させる。secretName は作成した secret を指定
controlplane:~$ k replace -f world.yaml --force
ingress.networking.k8s.io "world" deleted
ingress.networking.k8s.io/world replaced
アクセス確認してみます。
controlplane:~$ curl -kv https://world.universe.mine:30443/asia
--- snip ---
* SSL certificate verify result: self-signed certificate (18), continuing anyway.
* Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
# 作成した tls 証明書が提示されています。Okですね
最後の pathType を確認します。
- Prefix : /内の要素マッチング。例えば /app/ であれば app が対象
- Exact : 完全一致
- ImplementationSpecific : 利用する ingress controller の実装に依存する
rules:
- host: world.universe.mine
http:
paths:
- backend:
service:
name: europe
port:
number: 80
path: /europe
pathType: Prefix
- backend:
service:
name: asia
port:
number: 80
path: /asia
pathType: Prefix
あとがき
Kubernetes は奥が深い...