Підключення застосунків за допомогою Service

Модель Kubernetes для підключення контейнерів

Тепер, коли у вас є постійно працюючий, реплікований застосунок, ви можете дати до нього доступ з мережі.

Kubernetes передбачає, що кожен з Podʼів може спілкуватися з іншими, незалежно від того, на якому хості вони опиняються. Kubernetes надає кожному Podʼу власну IP-адресу, що є приватною адресою кластера, тому вам не потрібно явно створювати посилання між Podʼами або перенаправляти порти контейнера на порти хосту. Це означає, що контейнери всередині Podʼів можуть звертатися до портів один одного на localhost, і всі Podʼи в кластері можуть бачити один одного без NAT. У решті цього документа розглянуто, як ви можете запустити надійні сервіси на такій мережевій моделі.

У цьому посібнику використовується простий вебсервер nginx для демонстрації концепції.

Експонування Podʼів в кластер

Ми робили це в попередньому прикладі, але зробимо це ще раз і зосередимося на перспективі мережі. Створіть Pod nginx, і зверніть увагу, що він має специфікацію порту контейнера:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

Це робить його доступним з будь-якого вузла у вашому кластері. Перевірте вузли, на яких працює Pod:

kubectl apply -f ./run-my-nginx.yaml
kubectl get pods -l run=my-nginx -o wide
NAME                        READY     STATUS    RESTARTS   AGE       IP            NODE
my-nginx-3800858182-jr4a2   1/1       Running   0          13s       10.244.3.4    kubernetes-minion-905m
my-nginx-3800858182-kna2y   1/1       Running   0          13s       10.244.2.5    kubernetes-minion-ljyd

Перевірте IP-адреси ваших Podʼів:

kubectl get pods -l run=my-nginx -o custom-columns=POD_IP:.status.podIPs
    POD_IP
    [map[ip:10.244.3.4]]
    [map[ip:10.244.2.5]]

Ви повинні мати можливість увійти у будь-який вузол у своєму кластері за допомогою SSH і використовувати інструмент, такий як curl, щоб робити запити до обох IP-адрес. Зверніть увагу, що контейнери не використовують порт 80 на вузлі, і немає жодних спеціальних правил NAT для маршрутизації трафіку до Podʼів. Це означає, що ви можете запустити кілька Podʼів nginx на одному й тому ж вузлі, використовуючи той же containerPort, і отримувати доступ до них з будь-якого іншого Podʼа або вузла у вашому кластері, використовуючи призначену IP адресу Podʼа. Якщо ви хочете організувати перенаправлення певного порту на хості Вузла на резервні Podʼи, ви можете це зробити — але модель мережі повинна передбачати, що вам не потрібно цього робити.

Ви можете прочитати більше про Модель мережі Kubernetes якщо вас це цікавить.

Створення Service

Отже, у нас є Podʼи, що працюють з nginx у плоскому адресному просторі, доступному для всього кластера. Теоретично, ви можете звертатися до цих Podʼів безпосередньо, але що станеться, коли вузол вийде з ладу? Podʼи загинуть разом з ним, і ReplicaSet всередині Deployment створить нові, з іншими IP-адресами. Це проблема, яку вирішує Service.

Service Kubernetes — це абстракція, яка визначає логічний набір Podʼів, що працюють десь у вашому кластері, і всі надають однакову функціональність. Коли створюється Service, йому призначається унікальна IP-адреса (яку називають clusterIP). Ця адреса привʼязана до тривалості життя Service і не змінюється, поки Service живий. Podʼи можуть бути налаштовані для звернення до Service і знати, що звʼязок з Service буде автоматично балансуватися на деякий Pod, що є членом Service.

Ви можете створити Service для ваших двох реплік nginx за допомогою kubectl expose:

kubectl expose deployment/my-nginx
service/my-nginx exposed

Це еквівалентно kubectl apply -f наступного yaml:

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

Ця специфікація створить Service, який буде спрямований на TCP порт 80 на будь-якому Podʼі з міткою run: my-nginx і відкриє його на абстрактному порті Service (targetPort: це порт, на якому контейнер приймає трафік, port — це абстрактний порт Service, який може бути будь-яким портом, що використовується іншими Podʼами для доступу до Service). Перегляньте Service API обʼєкт, щоб побачити список підтримуваних полів у визначенні Service. Перевірте ваш Service:

kubectl get svc my-nginx
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
my-nginx   ClusterIP   10.0.162.149   <none>        80/TCP    21s

Як згадувалося раніше, Service підтримується групою Podʼів. Ці Podʼи експонуються через EndpointSlices. Селектор Service буде оцінюватися безперервно, і результати будуть надсилатися у EndpointSlice, який підключений до Service за допомогою мітки. Коли Pod припиняє існування, він автоматично видаляється з EndpointSlices, який містить його як точку доступу. Нові Podʼи, що відповідають селектору Service, автоматично додаються до EndpointSlice для цього Service. Перевірте точки доступу та зауважте, що IP-адреси збігаються з Podʼами, створеними на першому кроці:

kubectl describe svc my-nginx
Name:                my-nginx
Namespace:           default
Labels:              run=my-nginx
Annotations:         <none>
Selector:            run=my-nginx
Type:                ClusterIP
IP Family Policy:    SingleStack
IP Families:         IPv4
IP:                  10.0.162.149
IPs:                 10.0.162.149
Port:                <unset> 80/TCP
TargetPort:          80/TCP
Endpoints:           10.244.2.5:80,10.244.3.4:80
Session Affinity:    None
Events:              <none>
kubectl get endpointslices -l kubernetes.io/service-name=my-nginx
NAME             ADDRESSTYPE   PORTS   ENDPOINTS               AGE
my-nginx-7vzhx   IPv4          80      10.244.2.5,10.244.3.4   21s

Тепер ви повинні бути в змозі звертатися до nginx Service на <CLUSTER-IP>:<PORT> з будь-якого вузла у вашому кластері. Зауважте, що IP-адреса Service є повністю віртуальною, вона ніколи не передається мережею. Якщо вам цікаво, як це працює, ви можете прочитати більше про сервіс-проксі.

Доступ до Service

Kubernetes підтримує два основні режими знаходження Service — змінні середовища та DNS. Перший режим працює "з коробки", тоді як другий вимагає додаткового модуля CoreDNS cluster addon.

Змінні середовища

Коли Pod запускається на вузлі, kubelet додає набір змінних середовища для кожного активного Service. Це створює проблему з порядком. Щоб зрозуміти чому, перевірте середовище вашого працюючого Pod nginx (назва вашого Pod буде іншою):

kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443

Зверніть увагу, що ваш Service не згадується. Це тому, що ви створили репліки перед створенням Service. Іншим недоліком цього є те, що планувальник може розмістити обидва Podʼи на одній машині, що призведе до припинення роботи всього Service, якщо він вийде з ладу. Ми можемо зробити це прям зараз, видаливши 2 Podʼи та очікуючи, поки Deployment їх відновить. Цього разу Service існує до реплік. Це забезпечить рівномірний розподіл ваших Podʼів на рівні планувальника (за умови рівної потужності всіх вузлів), а також правильні змінні середовища:

kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2;

kubectl get pods -l run=my-nginx -o wide
NAME                        READY     STATUS    RESTARTS   AGE     IP            NODE
my-nginx-3800858182-e9ihh   1/1       Running   0          5s      10.244.2.7    kubernetes-minion-ljyd
my-nginx-3800858182-j4rm4   1/1       Running   0          5s      10.244.3.8    kubernetes-minion-905m

Ви можете помітити, що Podʼи мають різні імена, оскільки вони були видалені та відтворені.

kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE
KUBERNETES_SERVICE_PORT=443
MY_NGINX_SERVICE_HOST=10.0.162.149
KUBERNETES_SERVICE_HOST=10.0.0.1
MY_NGINX_SERVICE_PORT=80
KUBERNETES_SERVICE_PORT_HTTPS=443

DNS

Kubernetes пропонує DNS-сервіс, який автоматично призначає DNS-імена іншим Serviceʼам. Ви можете перевірити, чи він працює у вашому кластері:

kubectl get services kube-dns --namespace=kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.0.0.10    <none>        53/UDP,53/TCP   8m

Далі в цьому розділі ми будемо вважати, що у вас є Service із довготривалою IP-адресою (my-nginx), і DNS-сервер, який присвоїв цій IP-адресі імʼя. Ми використовуємо надбудову CoreDNS (назва застосунку kube-dns), тому ви можете звертатися до Service з будь-якого Pod у вашому кластері, використовуючи стандартні методи (наприклад, gethostbyname()). Якщо CoreDNS не працює, ви можете увімкнути його, звірившись з README CoreDNS або інформацією з Встановлення CoreDNS. Запустімо ще один застосунок curl для перевірки цього:

kubectl run curl --image=radial/busyboxplus:curl -i --tty --rm
Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false
Hit enter for command prompt

Потім натисніть Enter і запустіть nslookup my-nginx:

[ root@curl-131556218-9fnch:/ ]$ nslookup my-nginx
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      my-nginx
Address 1: 10.0.162.149

Захист Service

До цього моменту ми отримували доступ до сервера nginx лише всередині кластеру. Перед тим як виставити Service в Інтернет, вам потрібно переконатися, що канал звʼязку захищений. Для цього вам знадобиться:

  • Самопідписні сертифікати для https (якщо у вас немає ідентифікаційного сертифіката)
  • Сервер nginx, налаштований для використання сертифікатів
  • Secret, що робить сертифікати доступними для Pod

Ви можете отримати все це з прикладу nginx https. Це вимагає встановлення інструментів go та make. Якщо ви не хочете їх встановлювати, тоді дотримуйтесь ручних кроків, описаних нижче. Коротко:

make keys KEY=/tmp/nginx.key CERT=/tmp/nginx.crt
kubectl create secret tls nginxsecret --key /tmp/nginx.key --cert /tmp/nginx.crt
secret/nginxsecret created
kubectl get secrets
NAME                  TYPE                                  DATA      AGE
nginxsecret           kubernetes.io/tls                     2         1m

А також configmap:

kubectl create configmap nginxconfigmap --from-file=default.conf

Ви можете знайти приклад default.conf у репозиторії прикладів Kubernetes.

configmap/nginxconfigmap created
kubectl get configmaps
NAME             DATA   AGE
nginxconfigmap   1      114s

Ви можете переглянути деталі ConfigMap nginxconfigmap, використовуючи наступну команду:

kubectl describe configmap nginxconfigmap

Вихід буде схожим на:

Name:         nginxconfigmap
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
default.conf:
----
server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        listen 443 ssl;

        root /usr/share/nginx/html;
        index index.html;

        server_name localhost;
        ssl_certificate /etc/nginx/ssl/tls.crt;
        ssl_certificate_key /etc/nginx/ssl/tls.key;

        location / {
                try_files $uri $uri/ =404;
        }
}

BinaryData
====

Events:  <none>

Ось ручні кроки, яких слід дотримуватись у випадку, якщо у вас виникли проблеми з запуском make (наприклад, у Windows):

# Створіть пару відкритий/закритий ключ
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /d/tmp/nginx.key -out /d/tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx"
# Перетворіть ключі у кодування base64
cat /d/tmp/nginx.key | base64
cat /d/tmp/nginx.crt | base64

Скористайтесь виводом з попередньої команди для створення yaml-файлу. Закодовані у base64 значення мають бути в одному рядку.

apiVersion: "v1"
kind: "Secret"
metadata:
  name: "nginxsecret"
  namespace: "default"
type: kubernetes.io/tls
data:
  tls.crt: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIekNDQWdlZ0F3SUJBZ0lKQUp5M3lQK0pzMlpJTUEwR0NTcUdTSWIzRFFFQkJRVUFNQ1l4RVRBUEJnTlYKQkFNVENHNW5hVzU0YzNaak1SRXdEd1lEVlFRS0V3aHVaMmx1ZUhOMll6QWVGdzB4TnpFd01qWXdOekEzTVRKYQpGdzB4T0RFd01qWXdOekEzTVRKYU1DWXhFVEFQQmdOVkJBTVRDRzVuYVc1NGMzWmpNUkV3RHdZRFZRUUtFd2h1CloybHVlSE4yWXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSjFxSU1SOVdWM0IKMlZIQlRMRmtobDRONXljMEJxYUhIQktMSnJMcy8vdzZhU3hRS29GbHlJSU94NGUrMlN5ajBFcndCLzlYTnBwbQppeW1CL3JkRldkOXg5UWhBQUxCZkVaTmNiV3NsTVFVcnhBZW50VWt1dk1vLzgvMHRpbGhjc3paenJEYVJ4NEo5Ci82UVRtVVI3a0ZTWUpOWTVQZkR3cGc3dlVvaDZmZ1Voam92VG42eHNVR0M2QURVODBpNXFlZWhNeVI1N2lmU2YKNHZpaXdIY3hnL3lZR1JBRS9mRTRqakxCdmdONjc2SU90S01rZXV3R0ljNDFhd05tNnNTSzRqYUNGeGpYSnZaZQp2by9kTlEybHhHWCtKT2l3SEhXbXNhdGp4WTRaNVk3R1ZoK0QrWnYvcW1mMFgvbVY0Rmo1NzV3ajFMWVBocWtsCmdhSXZYRyt4U1FVQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjcKTUI4R0ExVWRJd1FZTUJhQUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjdNQXdHQTFVZEV3UUZNQU1CQWY4dwpEUVlKS29aSWh2Y05BUUVGQlFBRGdnRUJBRVhTMW9FU0lFaXdyMDhWcVA0K2NwTHI3TW5FMTducDBvMm14alFvCjRGb0RvRjdRZnZqeE04Tzd2TjB0clcxb2pGSW0vWDE4ZnZaL3k4ZzVaWG40Vm8zc3hKVmRBcStNZC9jTStzUGEKNmJjTkNUekZqeFpUV0UrKzE5NS9zb2dmOUZ3VDVDK3U2Q3B5N0M3MTZvUXRUakViV05VdEt4cXI0Nk1OZWNCMApwRFhWZmdWQTRadkR4NFo3S2RiZDY5eXM3OVFHYmg5ZW1PZ05NZFlsSUswSGt0ejF5WU4vbVpmK3FqTkJqbWZjCkNnMnlwbGQ0Wi8rUUNQZjl3SkoybFIrY2FnT0R4elBWcGxNSEcybzgvTHFDdnh6elZPUDUxeXdLZEtxaUMwSVEKQ0I5T2wwWW5scE9UNEh1b2hSUzBPOStlMm9KdFZsNUIyczRpbDlhZ3RTVXFxUlU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
  tls.key: "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2RhaURFZlZsZHdkbFIKd1V5eFpJWmVEZWNuTkFhbWh4d1NpeWF5N1AvOE9ta3NVQ3FCWmNpQ0RzZUh2dGtzbzlCSzhBZi9WemFhWm9zcApnZjYzUlZuZmNmVUlRQUN3WHhHVFhHMXJKVEVGSzhRSHA3VkpMcnpLUC9QOUxZcFlYTE0yYzZ3MmtjZUNmZitrCkU1bEVlNUJVbUNUV09UM3c4S1lPNzFLSWVuNEZJWTZMMDUrc2JGQmd1Z0ExUE5JdWFubm9UTWtlZTRuMG4rTDQKb3NCM01ZUDhtQmtRQlAzeE9JNHl3YjREZXUraURyU2pKSHJzQmlIT05Xc0RadXJFaXVJMmdoY1kxeWIyWHI2UAozVFVOcGNSbC9pVG9zQngxcHJHclk4V09HZVdPeGxZZmcvbWIvNnBuOUYvNWxlQlkrZStjSTlTMkQ0YXBKWUdpCkwxeHZzVWtGQWdNQkFBRUNnZ0VBZFhCK0xkbk8ySElOTGo5bWRsb25IUGlHWWVzZ294RGQwci9hQ1Zkank4dlEKTjIwL3FQWkUxek1yall6Ry9kVGhTMmMwc0QxaTBXSjdwR1lGb0xtdXlWTjltY0FXUTM5SjM0VHZaU2FFSWZWNgo5TE1jUHhNTmFsNjRLMFRVbUFQZytGam9QSFlhUUxLOERLOUtnNXNrSE5pOWNzMlY5ckd6VWlVZWtBL0RBUlBTClI3L2ZjUFBacDRuRWVBZmI3WTk1R1llb1p5V21SU3VKdlNyblBESGtUdW1vVlVWdkxMRHRzaG9reUxiTWVtN3oKMmJzVmpwSW1GTHJqbGtmQXlpNHg0WjJrV3YyMFRrdWtsZU1jaVlMbjk4QWxiRi9DSmRLM3QraTRoMTVlR2ZQegpoTnh3bk9QdlVTaDR2Q0o3c2Q5TmtEUGJvS2JneVVHOXBYamZhRGR2UVFLQmdRRFFLM01nUkhkQ1pKNVFqZWFKClFGdXF4cHdnNzhZTjQyL1NwenlUYmtGcVFoQWtyczJxWGx1MDZBRzhrZzIzQkswaHkzaE9zSGgxcXRVK3NHZVAKOWRERHBsUWV0ODZsY2FlR3hoc0V0L1R6cEdtNGFKSm5oNzVVaTVGZk9QTDhPTm1FZ3MxMVRhUldhNzZxelRyMgphRlpjQ2pWV1g0YnRSTHVwSkgrMjZnY0FhUUtCZ1FEQmxVSUUzTnNVOFBBZEYvL25sQVB5VWs1T3lDdWc3dmVyClUycXlrdXFzYnBkSi9hODViT1JhM05IVmpVM25uRGpHVHBWaE9JeXg5TEFrc2RwZEFjVmxvcG9HODhXYk9lMTAKMUdqbnkySmdDK3JVWUZiRGtpUGx1K09IYnRnOXFYcGJMSHBzUVpsMGhucDBYSFNYVm9CMUliQndnMGEyOFVadApCbFBtWmc2d1BRS0JnRHVIUVV2SDZHYTNDVUsxNFdmOFhIcFFnMU16M2VvWTBPQm5iSDRvZUZKZmcraEppSXlnCm9RN3hqWldVR3BIc3AyblRtcHErQWlSNzdyRVhsdlhtOElVU2FsbkNiRGlKY01Pc29RdFBZNS9NczJMRm5LQTQKaENmL0pWb2FtZm1nZEN0ZGtFMXNINE9MR2lJVHdEbTRpb0dWZGIwMllnbzFyb2htNUpLMUI3MkpBb0dBUW01UQpHNDhXOTVhL0w1eSt5dCsyZ3YvUHM2VnBvMjZlTzRNQ3lJazJVem9ZWE9IYnNkODJkaC8xT2sybGdHZlI2K3VuCnc1YytZUXRSTHlhQmd3MUtpbGhFZDBKTWU3cGpUSVpnQWJ0LzVPbnlDak9OVXN2aDJjS2lrQ1Z2dTZsZlBjNkQKckliT2ZIaHhxV0RZK2Q1TGN1YSt2NzJ0RkxhenJsSlBsRzlOZHhrQ2dZRUF5elIzT3UyMDNRVVV6bUlCRkwzZAp4Wm5XZ0JLSEo3TnNxcGFWb2RjL0d5aGVycjFDZzE2MmJaSjJDV2RsZkI0VEdtUjZZdmxTZEFOOFRwUWhFbUtKCnFBLzVzdHdxNWd0WGVLOVJmMWxXK29xNThRNTBxMmk1NVdUTThoSDZhTjlaMTltZ0FGdE5VdGNqQUx2dFYxdEYKWSs4WFJkSHJaRnBIWll2NWkwVW1VbGc9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"

Тепер створіть Secret, застосувавши файл:

kubectl apply -f nginxsecret.yaml
kubectl get secrets
NAME                  TYPE                                  DATA      AGE
nginxsecret           kubernetes.io/tls                     2         1m

Тепер змініть кількість реплік nginx для запуску сервера https використовуючи сертифікати з Secret та Service для експонування портів (80 та 443):

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    protocol: TCP
    name: https
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      - name: configmap-volume
        configMap:
          name: nginxconfigmap
      containers:
      - name: nginxhttps
        image: bprashanth/nginxhttps:1.0
        ports:
        - containerPort: 443
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
        - mountPath: /etc/nginx/conf.d
          name: configmap-volume

Примітні моменти про маніфест nginx-secure-app:

  • Він містить як специфікацію Deployment, так і Service в одному файлі.
  • nginx сервер обслуговує HTTP трафік на порту 80 та HTTPS трафік на порту 443, і Service nginx відкриває доступ до обох портів.
  • Кожен контейнер має доступ до ключів через том, змонтовану в /etc/nginx/ssl. Це налаштовується до запуску nginx сервера.
kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml

На цьому етапі ви можете отримати доступ до nginx сервера з будь-якого вузла.

kubectl get pods -l run=my-nginx -o custom-columns=POD_IP:.status.podIPs
    POD_IP
    [map[ip:10.244.3.5]]
node $ curl -k https://10.244.3.5
...
<h1>Welcome to nginx!</h1>

Зверніть увагу, що ми використовували параметр -k для curl на останньому етапі, тому що ми нічого не знаємо про Podʼи, що виконують nginx під час генерації сертифіката, тому ми повинні сказати curl ігнорувати невідповідність CName. Створюючи Service, ми повʼязали CName, який використовується в сертифікаті, з фактичним DNS-імʼям, що використовується Podʼами під час пошуку Service. Перевірмо це з Podʼа (для простоти використовується той же Secret, Podʼу потрібен лише nginx.crt для доступу до Service):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl-deployment
spec:
  selector:
    matchLabels:
      app: curlpod
  replicas: 1
  template:
    metadata:
      labels:
        app: curlpod
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: curlpod
        command:
        - sh
        - -c
        - while true; do sleep 1; done
        image: radial/busyboxplus:curl
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
kubectl apply -f ./curlpod.yaml
kubectl get pods -l app=curlpod
NAME                               READY     STATUS    RESTARTS   AGE
curl-deployment-1515033274-1410r   1/1       Running   0          1m
kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/tls.crt
...
<title>Welcome to nginx!</title>
...

Експонування Service

Для деяких частин ваших застосунків ви можете захотіти експонувати Service на зовнішню IP-адресу. Kubernetes підтримує два способи: NodePorts та LoadBalancers. Service, створений у попередньому розділі, вже використовував NodePort, тому ваша репліка nginx HTTPS готова обслуговувати трафік з інтернету, якщо ваш вузол має публічну IP-адресу.

kubectl get svc my-nginx -o yaml | grep nodePort -C 5
  uid: 07191fb3-f61a-11e5-8ae5-42010af00002
spec:
  clusterIP: 10.0.162.149
  ports:
  - name: http
    nodePort: 31704
    port: 8080
    protocol: TCP
    targetPort: 80
  - name: https
    nodePort: 32453
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    run: my-nginx
kubectl get nodes -o yaml | grep ExternalIP -C 1
    - address: 104.197.41.11
      type: ExternalIP
    allocatable:
--
    - address: 23.251.152.56
      type: ExternalIP
    allocatable:
...

$ curl https://<EXTERNAL-IP>:<NODE-PORT> -k
...
<h1>Welcome to nginx!</h1>

Тепер створімо Service знову, використовуючи хмарний балансувальник навантаження. Змініть Type Service my-nginx з NodePort на LoadBalancer:

kubectl edit svc my-nginx
kubectl get svc my-nginx
NAME       TYPE           CLUSTER-IP     EXTERNAL-IP        PORT(S)               AGE
my-nginx   LoadBalancer   10.0.162.149   xx.xxx.xxx.xxx     8080:30163/TCP        21s
curl https://<EXTERNAL-IP> -k
...
<title>Welcome to nginx!</title>

IP-адреса в колонці EXTERNAL-IP доступна в інтернеті. CLUSTER-IP доступна тільки всередині вашого кластера/приватної хмарної мережі.

Зверніть увагу, що у AWS тип LoadBalancer створює ELB, який використовує (довге) імʼя хосту, а не IP. Воно занадто довге, щоб поміститися в стандартному виводі kubectl get svc, тому вам потрібно виконати kubectl describe service my-nginx, щоб побачити його. Ви побачите щось на кшталт:

kubectl describe service my-nginx
...
LoadBalancer Ingress:   a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com
...

Що далі

Змінено June 20, 2024 at 12:44 PM PST: Sync changest from andygol/k8s-website (36d05bc8a1)