Я бился головой об эту стену некоторое время. В Интернете много информации о Kubernetes, но все это предполагает столько знаний, что n00bs, таким как я, на самом деле особо нечем заняться.
Итак, кто-нибудь может поделиться простым примером следующего (в виде файла yaml)? Все, что я хочу, это
- две капсулы
- скажем, у одного модуля есть бэкэнд (я не знаю - node.js), а у другого - внешний интерфейс (скажем, React).
- Способ связи между ними.
А затем пример вызова API-интерфейса от задней панели к передней.
Я начинаю изучать подобные вещи, и внезапно я попадаю на эту страницу - https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-achieve-this. Это супер бесполезно . Я не хочу и не нуждаюсь в расширенных сетевых политиках, и при этом у меня нет времени проходить через несколько разных уровней обслуживания, которые отображаются поверх kubernetes. Я просто хочу выяснить тривиальный пример сетевого запроса.
Надеемся, что если этот пример существует в стеке, он также будет полезен другим людям.
Любая помощь будет оценена. Спасибо.
EDIT; похоже, что самым простым примером может быть использование контроллера Ingress.
РЕДАКТИРОВАТЬ, РЕДАКТИРОВАТЬ;
Я работаю, чтобы попытаться развернуть минимальный пример - я пройдусь по некоторым шагам здесь и укажу на мои проблемы.
Ниже приведен мой yaml
файл:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: frontend
labels:
app: frontend
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: nginx
image: patientplatypus/frontend_example
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: LoadBalancer
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 3000
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: backend
labels:
app: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: nginx
image: patientplatypus/backend_example
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: LoadBalancer
selector:
app: backend
ports:
- protocol: TCP
port: 80
targetPort: 5000
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: frontend
spec:
rules:
- host: www.kubeplaytime.example
http:
paths:
- path: /
backend:
serviceName: frontend
servicePort: 80
- path: /api
backend:
serviceName: backend
servicePort: 80
Я считаю, что это делает
Развертывание внешнего и внешнего приложений - я развернул patientplatypus/frontend_example
и patientplatypus/backend_example
в dockerhub, а затем потянул изображения вниз. Один открытый вопрос, который у меня есть: что, если я не хочу извлекать изображения из док-станции и, скорее, просто хочу загрузить их с моего локального хоста, это возможно? В этом случае я отправляю свой код на рабочий сервер, собираю образы докеров на сервере и затем загружаю их в kubernetes. Преимущество заключается в том, что мне не нужно полагаться на dockerhub, если я хочу, чтобы мои изображения были приватными.
Он создает две конечные точки службы, которые направляют внешний трафик из веб-браузера в каждое из развертываний. Эти сервисы относятся к типу loadBalancer
, потому что они балансируют трафик между (в данном случае 3) репликациями, которые у меня есть в развертываниях.
Наконец, у меня есть входной контроллер, который предполагается , чтобы мои службы могли перенаправляться друг к другу через www.kubeplaytime.example
и www.kubeplaytime.example/api
. Однако это не работает.
Что происходит, когда я запускаю это?
patientplatypus:~/Documents/kubePlay:09:17:50$kubectl create -f kube-deploy.yaml
deployment.apps "frontend" created
service "frontend" created
deployment.apps "backend" created
service "backend" created
ingress.extensions "frontend" created
Итак, во-первых, создается впечатление, что все детали мне нужны без ошибок.
patientplatypus:~/Documents/kubePlay:09:22:30$kubectl get --watch services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend LoadBalancer 10.0.18.174 <pending> 80:31649/TCP 1m
frontend LoadBalancer 10.0.100.65 <pending> 80:32635/TCP 1m
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 10d
frontend LoadBalancer 10.0.100.65 138.91.126.178 80:32635/TCP 2m
backend LoadBalancer 10.0.18.174 138.91.121.182 80:31649/TCP 2m
Во-вторых, если я смотрю сервисы, я в конечном итоге получаю IP-адреса, которые я могу использовать для перехода в своем браузере на эти сайты. Каждый из вышеперечисленных IP-адресов работает при маршрутизации меня к внешнему интерфейсу и внутреннему интерфейсу соответственно.
ОДНАКО
У меня возникает проблема, когда я пытаюсь использовать входной контроллер - он, кажется, развернут, но я не знаю, как туда добраться.
patientplatypus:~/Documents/kubePlay:09:24:44$kubectl get ingresses
NAME HOSTS ADDRESS PORTS AGE
frontend www.kubeplaytime.example 80 16m
- Таким образом, у меня нет адреса, который я могу использовать, и
www.kubeplaytime.example
не работает.
Похоже, что мне нужно сделать, чтобы маршрутизировать к входному расширению, которое я только что создал, - это использовать службу и развертывание на it для получения IP-адреса, но это начинает выглядеть невероятно сложным очень быстро.
Например, взгляните на эту статью среднего размера: https://medium.com/@cashisclay/kubernetes-ingress-82aa960f658e.
Может показаться, что необходимый код, добавляемый только для маршрутизации службы к входу (т.е. то, что он называет Ingress Controller ), выглядит так:
---
kind: Service
apiVersion: v1
metadata:
name: ingress-nginx
spec:
type: LoadBalancer
selector:
app: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: ingress-nginx
spec:
replicas: 1
template:
metadata:
labels:
app: ingress-nginx
spec:
terminationGracePeriodSeconds: 60
containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.8.3
name: ingress-nginx
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/nginx-default-backend
---
kind: Service
apiVersion: v1
metadata:
name: nginx-default-backend
spec:
ports:
- port: 80
targetPort: http
selector:
app: nginx-default-backend
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx-default-backend
spec:
replicas: 1
template:
metadata:
labels:
app: nginx-default-backend
spec:
terminationGracePeriodSeconds: 60
containers:
- name: default-http-backend
image: gcr.io/google_containers/defaultbackend:1.0
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
ports:
- name: http
containerPort: 8080
protocol: TCP
Это, казалось бы, нужно добавить к моему другому yaml
коду выше, чтобы получить точку входа в службу для моей входящей маршрутизации, и она, похоже, дает ip:
patientplatypus:~/Documents/kubePlay:09:54:12$kubectl get --watch services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend LoadBalancer 10.0.31.209 <pending> 80:32428/TCP 4m
frontend LoadBalancer 10.0.222.47 <pending> 80:32482/TCP 4m
ingress-nginx LoadBalancer 10.0.28.157 <pending> 80:30573/TCP,443:30802/TCP 4m
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 10d
nginx-default-backend ClusterIP 10.0.71.121 <none> 80/TCP 4m
frontend LoadBalancer 10.0.222.47 40.121.7.66 80:32482/TCP 5m
ingress-nginx LoadBalancer 10.0.28.157 40.121.6.179 80:30573/TCP,443:30802/TCP 6m
backend LoadBalancer 10.0.31.209 40.117.248.73 80:32428/TCP 7m
Так что ingress-nginx
- это сайт, на который я хочу попасть. Переход к 40.121.6.179
возвращает сообщение 404 по умолчанию (default backend - 404
) - оно не переходит к frontend
, как /
, что необходимо для маршрутизации. /api
возвращает то же самое. Переход к моему пространству имен хоста www.kubeplaytime.example
возвращает 404 из браузера - без обработки ошибок.
ВОПРОСЫ
Строго ли необходим контроллер входа, и если да, то есть ли менее сложная версия этого?
Я чувствую, что я рядом, что я делаю не так?
ПОЛНЫЙ ЯМЛ
Доступно здесь: https://gist.github.com/patientplatypus/fa07648339ee6538616cb69282a84938
Спасибо за помощь!
РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ
Я пытался использовать HELM . На первый взгляд это простой интерфейс, и я попытался его раскрутить:
patientplatypus:~/Documents/kubePlay:12:13:00$helm install stable/nginx-ingress
NAME: erstwhile-beetle
LAST DEPLOYED: Sun May 6 12:13:30 2018
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
erstwhile-beetle-nginx-ingress-controller 1 1s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
erstwhile-beetle-nginx-ingress-controller LoadBalancer 10.0.216.38 <pending> 80:31494/TCP,443:32118/TCP 1s
erstwhile-beetle-nginx-ingress-default-backend ClusterIP 10.0.55.224 <none> 80/TCP 1s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
erstwhile-beetle-nginx-ingress-controller 1 1 1 0 1s
erstwhile-beetle-nginx-ingress-default-backend 1 1 1 0 1s
==> v1beta1/PodDisruptionBudget
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
erstwhile-beetle-nginx-ingress-controller 1 N/A 0 1s
erstwhile-beetle-nginx-ingress-default-backend 1 N/A 0 1s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
erstwhile-beetle-nginx-ingress-controller-7df9b78b64-24hwz 0/1 ContainerCreating 0 1s
erstwhile-beetle-nginx-ingress-default-backend-849b8df477-gzv8w 0/1 ContainerCreating 0 1s
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 default get services -o wide -w erstwhile-beetle-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
Кажется, это действительно хорошо - все раскручивается и дает пример того, как добавить вход. Так как я развернул руль в пустом kubectl
, я использовал следующий файл yaml
, чтобы добавить то, что, как я думал, потребуется.
Файл:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: frontend
labels:
app: frontend
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: nginx
image: patientplatypus/frontend_example
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
type: LoadBalancer
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 3000
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: backend
labels:
app: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: nginx
image: patientplatypus/backend_example
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
type: LoadBalancer
selector:
app: backend
ports:
- protocol: TCP
port: 80
targetPort: 5000
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: www.example.com
http:
paths:
- path: /api
backend:
serviceName: backend
servicePort: 80
- path: /
frontend:
serviceName: frontend
servicePort: 80
Развертывание этого в кластере, однако, приводит к этой ошибке:
patientplatypus:~/Documents/kubePlay:11:44:20$kubectl create -f kube-deploy.yaml
deployment.apps "frontend" created
service "frontend" created
deployment.apps "backend" created
service "backend" created
error: error validating "kube-deploy.yaml": error validating data: [ValidationError(Ingress.spec.rules[0].http.paths[1]): unknown field "frontend" in io.k8s.api.extensions.v1beta1.HTTPIngressPath, ValidationError(Ingress.spec.rules[0].http.paths[1]): missing required field "backend" in io.k8s.api.extensions.v1beta1.HTTPIngressPath]; if you choose to ignore these errors, turn validation off with --validate=false
Итак, возникает вопрос: ну что за хрень, как мне это отладить?
Если вы выплевываете код, который производит helm, он в основном не читается человеком - нет никакого способа пойти туда и выяснить, что происходит.
Проверьте это: https://gist.github.com/patientplatypus/0e281bf61307f02e16e0091397a1d863 - более 1000 строк!
Если у кого-то есть лучший способ отладить развертывание руля, добавьте его в список открытых вопросов.
РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ
Для упрощения в крайнем случае Я пытаюсь позвонить из одного модуля в другой, используя только пространство имен.
Итак, вот мой код React, где я делаю http-запрос:
axios.get('http://backend/test')
.then(response=>{
console.log('return from backend and response: ', response);
})
.catch(error=>{
console.log('return from backend and error: ', error);
})
Я также пытался использовать http://backend.exampledeploy.svc.cluster.local/test
без удачи.
Вот мой код узла, обрабатывающий get:
router.get('/test', function(req, res, next) {
res.json({"test":"test"})
});
Вот мой yaml
файл, который я загружаю в кластер kubectl
:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: frontend
namespace: exampledeploy
labels:
app: frontend
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: nginx
image: patientplatypus/frontend_example
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: exampledeploy
spec:
type: LoadBalancer
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 3000
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: backend
namespace: exampledeploy
labels:
app: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: nginx
image: patientplatypus/backend_example
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: exampledeploy
spec:
type: LoadBalancer
selector:
app: backend
ports:
- protocol: TCP
port: 80
targetPort: 5000
Загрузка в кластер работает, как я вижу в моем терминале:
patientplatypus:~/Documents/kubePlay:14:33:20$kubectl get all --namespace=exampledeploy
NAME READY STATUS RESTARTS AGE
pod/backend-584c5c59bc-5wkb4 1/1 Running 0 15m
pod/backend-584c5c59bc-jsr4m 1/1 Running 0 15m
pod/backend-584c5c59bc-txgw5 1/1 Running 0 15m
pod/frontend-647c99cdcf-2mmvn 1/1 Running 0 15m
pod/frontend-647c99cdcf-79sq5 1/1 Running 0 15m
pod/frontend-647c99cdcf-r5bvg 1/1 Running 0 15m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/backend LoadBalancer 10.0.112.160 168.62.175.155 80:31498/TCP 15m
service/frontend LoadBalancer 10.0.246.212 168.62.37.100 80:31139/TCP 15m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.extensions/backend 3 3 3 3 15m
deployment.extensions/frontend 3 3 3 3 15m
NAME DESIRED CURRENT READY AGE
replicaset.extensions/backend-584c5c59bc 3 3 3 15m
replicaset.extensions/frontend-647c99cdcf 3 3 3 15m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/backend 3 3 3 3 15m
deployment.apps/frontend 3 3 3 3 15m
NAME DESIRED CURRENT READY AGE
replicaset.apps/backend-584c5c59bc 3 3 3 15m
replicaset.apps/frontend-647c99cdcf 3 3 3 15m
Однако, когда я пытаюсь сделать запрос, я получаю следующую ошибку:
return from backend and error:
Error: Network Error
Stack trace:
createError@http://168.62.37.100/static/js/bundle.js:1555:15
handleError@http://168.62.37.100/static/js/bundle.js:1091:14
App.js:14
Поскольку вызов axios
осуществляется из браузера, мне интересно, если просто невозможно использовать этот метод для вызова бэкэнда, даже если бэкэнд и внешний интерфейс находятся в разных модулях. Я немного растерялся, так как думал, что это самый простой из возможных способов объединения сетевых модулей.
РЕДАКТИРОВАТЬ X5
Я определил, что можно свернуть серверную часть из командной строки, выполнив код в модуле так:
patientplatypus:~/Documents/kubePlay:15:25:25$kubectl exec -ti frontend-647c99cdcf-5mfz4 --namespace=exampledeploy -- curl -v http://backend/test
* Hostname was NOT found in DNS cache
* Trying 10.0.249.147...
* Connected to backend (10.0.249.147) port 80 (#0)
> GET /test HTTP/1.1
> User-Agent: curl/7.38.0
> Host: backend
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 15
< ETag: W/"f-SzkCEKs7NV6rxiz4/VbpzPnLKEM"
< Date: Sun, 06 May 2018 20:25:49 GMT
< Connection: keep-alive
<
* Connection #0 to host backend left intact
{"test":"test"}
Что это означает, без сомнения, потому что код переднего плана выполняется в браузере, ему необходим Ingress для получения доступа к модулю, так как запросы http от внешнего интерфейса - это то, что ломает простую сеть под модулем. Я не был уверен в этом, но это означает, что необходим вход.