Небольшая заметка, на тему запуска vue.js в kubernetes кластере

от автора

image
Это небольшая заметка на тему как запаковать vue.js приложение в Dockerfile и потом его запустить в контейнере в kubernetes’e.

Что делает

Я написал небольшую программку, которая генерирует номер свободного NodePort. Собственно ничего особо полезного она не делает, но можно не парится с поиском порта, ну и так для интереса посмотреть, как такое можно делать.

Начали

Весь проект состоит из друх частей — frontend и server. Фронтент спрашивает nodePort у сервера, а серверная часть через kubernetes api находит какой-нибудь свободный.
Собственно чтобы это всё работало в докере, надо вынести некоторые переменные из приложения, такие как адрес kubernetes api, порт, токен, итд.
Выглядит это так:

k8s-nodeport-gen/server/index.js: var k8sInfo = {   url: process.env.K8SURL,   port: process.env.K8SPORT,   timeout: process.env.K8STIMEOUT || '30',   respath: process.env.RESSPATH || '/api/v1/services',   token: process.env.K8STOKEN,   nodePortStart: process.env.K8SPORTSTART || '30000',   nodePortEnd: process.env.K8SPORTEND || '32000' } app.listen(process.env.PORT || 8081)

Cкажем, что всё протестировали и наше приложение работает.

Создаём докер образ

Те, кто работал с vue.js знает, что там куча всяких файлов, для чего они все нужны я не знаю, но видать нужны. Но благодаря тому, что есть такая вещь как vue-cli, всё можно довольно просто упаковать. Теперь всё пакуем:

npm run build

После этого у нас появится папка «dist» и файл «index.html» в «k8s-nodeport-gen/client». И для работы нам нужны только они. То есть по идее чтобы работал фронтенд надо какой-нибудь http сервер. Но в данном случае есть ещё и бэкенд, который тоже должен работать. По этому в моём случае как http сервер будет работать node.js express.
Файлы будут позде лежать в папке k8s-nodeport-gen/public. Для этого добавляем опцию в server/index.js

app.use(express.static(__dirname + '/public'))

Теперь когда разобрали с файлами можно создать Dockerfile. Нам из фронтенда надо только создать файлы для папки «dist». Для этого мы воспользуемся такой новомодной штукой, как multistage build.

FROM node:10-alpine AS base COPY client /portgen/client COPY server /portgen/server WORKDIR /portgen RUN cd client && npm i && npm run build  FROM node:10-alpine  WORKDIR /portgen COPY server/index.js /portgen/index.js COPY server/package.json /portgen/package.json COPY --from=base /portgen/client/dist ./public RUN npm i  CMD ["/usr/local/bin/node", "/portgen/index.js"]

То есть в первом контейнере запускаем «npm run build», а во втором контейнере копируем файлы из «dist» в «public». В конце у нас получается образ в 95мб.
Теперь у нас есть docker образ, который я уже залил на hub.docker.com.

Запуск

Теперь мы хотим запустить этот образ в kubernetes’e, к тому же нам нужен токен, который может через kubernetes api видеть какие порты уже используются.

Для этого надо надо создать сервесный аккаунт, роль(можно использовать уже существующую) и rolebinding (не знаю как правильно перевести).
У меня в кластере уже есть кластерная роль «view»

ceku@ceku1> kubectl describe clusterrole view Name:         view Labels:       kubernetes.io/bootstrapping=rbac-defaults Annotations:  rbac.authorization.kubernetes.io/autoupdate=true PolicyRule:   Resources                                Non-Resource URLs  Resource Names  Verbs   ---------                                -----------------  --------------  -----   bindings                                 []                 []              [get list watch]   configmaps                               []                 []              [get list watch]   endpoints                                []                 []              [get list watch]   events                                   []                 []              [get list watch]   limitranges                              []                 []              [get list watch]   namespaces                               []                 []              [get list watch]   namespaces/status                        []                 []              [get list watch]   persistentvolumeclaims                   []                 []              [get list watch]   pods                                     []                 []              [get list watch]   pods/log                                 []                 []              [get list watch]   pods/status                              []                 []              [get list watch]   replicationcontrollers                   []                 []              [get list watch]   replicationcontrollers/scale             []                 []              [get list watch]   replicationcontrollers/status            []                 []              [get list watch]   resourcequotas                           []                 []              [get list watch]   resourcequotas/status                    []                 []              [get list watch]   serviceaccounts                          []                 []              [get list watch]   services                                 []                 []              [get list watch]   daemonsets.apps                          []                 []              [get list watch]   deployments.apps                         []                 []              [get list watch]   deployments.apps/scale                   []                 []              [get list watch]   replicasets.apps                         []                 []              [get list watch]   replicasets.apps/scale                   []                 []              [get list watch]   statefulsets.apps                        []                 []              [get list watch]   horizontalpodautoscalers.autoscaling     []                 []              [get list watch]   cronjobs.batch                           []                 []              [get list watch]   jobs.batch                               []                 []              [get list watch]   daemonsets.extensions                    []                 []              [get list watch]   deployments.extensions                   []                 []              [get list watch]   deployments.extensions/scale             []                 []              [get list watch]   ingresses.extensions                     []                 []              [get list watch]   networkpolicies.extensions               []                 []              [get list watch]   replicasets.extensions                   []                 []              [get list watch]   replicasets.extensions/scale             []                 []              [get list watch]   replicationcontrollers.extensions/scale  []                 []              [get list watch]   networkpolicies.networking.k8s.io        []                 []              [get list watch]   poddisruptionbudgets.policy              []                 []              [get list watch]

Теперь создадим аккаунт и rolebinding
account_portng.yml:

apiVersion: v1 kind: ServiceAccount metadata:   name: portng-service-get   namespace: internal   labels:     k8s-app: portng-service-get     kubernetes.io/cluster-service: "true"

rolebindng_portng.yml:

kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata:   namespace: internal   name: view   labels:     k8s-app: portng-service-get     kubernetes.io/cluster-service: "true"     addonmanager.kubernetes.io/mode: Reconcile subjects: - kind: ServiceAccount   name: portng-service-get   namespace: kube-system   apiGroup: "" roleRef:   kind: ClusterRole   name: view   apiGroup: ""

Теперь у нас есть аккаунт, а у него есть токен. Его название написано в аккаунте:

ceku@ceku1 /a/r/aditointernprod.aditosoftware.local> kubectl get serviceaccount portng-service-get -n internal -o yaml apiVersion: v1 kind: ServiceAccount metadata:   creationTimestamp: 2018-08-02T07:31:54Z   labels:     k8s-app: portng-service-get     kubernetes.io/cluster-service: "true"   name: portng-service-get   namespace: internal   resourceVersion: "7270593"   selfLink: /api/v1/namespaces/internal/serviceaccounts/portng-service-get   uid: 2153dfa0-9626-11e8-aaa3-ac1f6b664c1c secrets: - name: portng-service-get-token-vr5bj

Теперь надо только написать deploy, service, ingress для страницы. Начнём:
deploy_portng.yml

apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1 kind: Deployment metadata:   namespace: internal   name: portng.server.local spec:   replicas: 1   template:     metadata:       labels:         app: portng.server.local     spec:       serviceAccountName: portng-service-get       containers:       - name: portgen         image: de1m/k8s-nodeport-gen         env:         - name: K8SURL           value: ceku.server.local         - name: K8SPORT           value: '6443'         - name: K8STIMEOUT           value: '30'         - name: RESSPATH           value: '/api/v1/services'         - name: K8SPORTSTART           value: '30000'         - name: K8SPORTEND           value: '32000'         - name: PORT           value: '8080'         args:         - /bin/sh         - -c         - export K8STOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) && node /portgen/index.js

Здесь надо обратить внимание на две вещи, это «serviceAccountName: portng-service-get» и токен для kubernetes’a, точнее говоря то, как я его добавил.

Теперь напишем сервис:
svc_portng.yml

apiVersion: v1 kind: Service metadata:   name: portng-server-local   namespace: internal spec:   ports:   - name: http     port: 8080     targetPort: 8080   selector:     app: portng.server.local

И ingress, для него у вас должен быть установлен ingress controller
ingress_portng.yaml:

apiVersion: extensions/v1beta1 kind: Ingress metadata:   name: portng.aditosoftware.local   namespace: internal   annotations:     kubernetes.io/ingress.class: "internal" spec:   rules:   - host: portng.server.local     http:       paths:       - path: /         backend:           serviceName: portng-server-local           servicePort: 8080

Всё, осталось только закинуть файлы на сервер и запустить.
Всё это можно запустить и как докер контейнер и даже без него, но часть с аккаунтами в kubernetes’e всё равно придётся проходить.

Ресурсы:

Docker образ на hub.docker.com
Git репозиторий на github.com

Как вы видете, ничего особого в данной статье нету, но для некоторых я думаю будет интересно.


ссылка на оригинал статьи https://habr.com/post/419033/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *