Como implantar um aplicativo Ruby on Rails com o HAProxy Ingress, unicorn / puma e soquetes da web

Após meses de teste, finalmente transportamos o aplicativo Ruby on Rails para produção com o cluster Kubernetes.


Neste artigo, mostrarei como configurar o roteamento baseado em caminho para um aplicativo Kubernetes Ruby on Rails com um controlador HAProxy Ingress.


imagem


Supõe-se que você tenha alguma idéia do que são pods , implantações , serviços , um mapa de configuração e o Ingress no Kubernetes.


Geralmente, em um aplicativo Rails, existem serviços como unicórnio / puma, sidekiq / trabalho atrasado / resque, soquetes da web e vários serviços API especiais. Tínhamos um serviço da web aberto através do balanceador e tudo funcionava bem. Mas o tráfego cresceu e foi necessário rotear por URL ou caminho.


O Kubernetes não possui uma solução pronta para balancear esse tipo de carga. Um controlador de entrada de albestá sendo desenvolvido para ele, mas ainda não está no estágio alfa e para produção.


Para o roteamento baseado em caminho, era melhor usar um controlador do Ingress .


Estudamos a questão e descobrimos que o k8s tem soluções diferentes para o Ingress.



Experimentamos o nginx-ingress e o HAProxy e decidimos pelo HAProxy - é melhor para os soquetes da web Rails que usamos no projeto.


Vou mostrar passo a passo como anexar o HAProxy Ingress a um aplicativo Rails.


Configurando um aplicativo Rails com um controlador HAProxy Ingress


Aqui está o que faremos:


  • Vamos criar um aplicativo Rails com diferentes serviços e implantações.
  • Crie um segredo TLS para SSL.
  • Crie um mapa de configuração do HAProxy Ingress.
  • Crie um controlador HAProxy Ingress.
  • Vamos abrir o acesso ao Ingress através de um serviço como o LoadBalancer.
  • Vamos configurar aplicativos DNS para o serviço Ingress.
  • Crie regras diferentes do Ingress para roteamento baseado em caminho.
  • Roteamento de teste com base no caminho.

Vamos criar um manifesto para implantar um aplicativo Rails para diferentes serviços - web (unicórnio), tarefas em segundo plano (sidekiq), soquete da web (ruby thin), API (unicorn dedicado).


Aqui está nosso modelo de serviço e aplicativo da Web de implantação.


--- apiVersion: v1 kind: Deployment metadata: name: test-production-web labels: app: test-production-web namespace: test spec: template: metadata: labels: app: test-production-web spec: containers: - image: <your-repo>/<your-image-name>:latest name: test-production imagePullPolicy: Always env: - name: POSTGRES_HOST value: test-production-postgres - name: REDIS_HOST value: test-production-redis - name: APP_ENV value: production - name: APP_TYPE value: web - name: CLIENT value: test ports: - containerPort: 80 imagePullSecrets: - name: registrykey --- apiVersion: v1 kind: Service metadata: name: test-production-web labels: app: test-production-web namespace: test spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: test-production-web 

Aqui está o modelo de serviço e implantação de aplicativos em segundo plano.


 --- apiVersion: v1 kind: Deployment metadata: name: test-production-background labels: app: test-production-background namespace: test spec: template: metadata: labels: app: test-production-background spec: containers: - image: <your-repo>/<your-image-name>:latest name: test-production imagePullPolicy: Always env: - name: POSTGRES_HOST value: test-production-postgres - name: REDIS_HOST value: test-production-redis - name: APP_ENV value: production - name: APP_TYPE value: background - name: CLIENT value: test ports: - containerPort: 80 imagePullSecrets: - name: registrykey --- apiVersion: v1 kind: Service metadata: name: test-production-background labels: app: test-production-background namespace: test spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: test-production-background 

Aqui está o soquete do aplicativo da web de implantação e o modelo de serviço.


 --- apiVersion: v1 kind: Deployment metadata: name: test-production-websocket labels: app: test-production-websocket namespace: test spec: template: metadata: labels: app: test-production-websocket spec: containers: - image: <your-repo>/<your-image-name>:latest name: test-production imagePullPolicy: Always env: - name: POSTGRES_HOST value: test-production-postgres - name: REDIS_HOST value: test-production-redis - name: APP_ENV value: production - name: APP_TYPE value: websocket - name: CLIENT value: test ports: - containerPort: 80 imagePullSecrets: - name: registrykey --- apiVersion: v1 kind: Service metadata: name: test-production-websocket labels: app: test-production-websocket namespace: test spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: test-production-websocket 

Aqui estão as informações de implantação e serviço da API do aplicativo.


 --- `apiVersion: v1 kind: Deployment metadata: name: test-production-api labels: app: test-production-api namespace: test spec: template: metadata: labels: app: test-production-api spec: containers: - image: <your-repo>/<your-image-name>:latest name: test-production imagePullPolicy: Always env: - name: POSTGRES_HOST value: test-production-postgres - name: REDIS_HOST value: test-production-redis - name: APP_ENV value: production - name: APP_TYPE value: api - name: CLIENT value: test ports: - containerPort: 80 imagePullSecrets: - name: registrykey --- apiVersion: v1 kind: Service metadata: name: test-production-api labels: app: test-production-api namespace: test spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: test-production-api 

Vamos executar o manifesto com o kubectl apply .


 $ kubectl apply -f test-web.yml -f test-background.yml -f test-websocket.yml -f test-api.yml deployment "test-production-web" created service "test-production-web" created deployment "test-production-background" created service "test-production-background" created deployment "test-production-websocket" created service "test-production-websocket" created deployment "test-production-api" created service "test-production-api" created 

Depois que o aplicativo for implantado e iniciado, você precisará criar um ingresso HAProxy. Mas primeiro, vamos criar um segredo TLS com uma chave e certificado SSL.


Ele permitirá HTTPS para o URL do aplicativo e o encerrará no L7.


$ kubectl create secret tls tls-certificate --key server.key --cert server.pem


server.key aqui é a nossa chave SSL e server.pem é o nosso certificado SSL no formato pem.


Agora crie os recursos do controlador HAProxy.


Mapa de configuração do HAProxy


Veja todas as opções de configuração disponíveis para o HAProxy aqui .


 apiVersion: v1 data: dynamic-scaling: "true" backend-server-slots-increment: "4" kind: ConfigMap metadata: name: haproxy-configmap namespace: test 

Implantação do controlador HAProxy Ingress


Padrão de implantação para um controlador do Ingress com pelo menos duas réplicas para gerenciar uma implantação seqüencial.


 apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: run: haproxy-ingress name: haproxy-ingress namespace: test spec: replicas: 2 selector: matchLabels: run: haproxy-ingress template: metadata: labels: run: haproxy-ingress spec: containers: - name: haproxy-ingress image: quay.io/jcmoraisjr/haproxy-ingress:v0.5-beta.1 args: - --default-backend-service=$(POD_NAMESPACE)/test-production-web - --default-ssl-certificate=$(POD_NAMESPACE)/tls-certificate - --configmap=$(POD_NAMESPACE)/haproxy-configmap - --ingress-class=haproxy ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: stat containerPort: 1936 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace 

Neste manifesto, estamos particularmente interessados ​​nos argumentos transmitidos ao controlador.
--default-backend-service é o serviço que o aplicativo usará se nenhuma regra corresponder à solicitação.


Temos esse serviço de test-production-web , mas pode ser uma página 404 personalizada ou algo assim - você decide.


--default-ssl-certificate é o segredo SSL que acabamos de criar. Ele encerrará o SSL no L7 e o aplicativo estará acessível externamente via HTTPS.


Serviço de ingresso HAProxy


Este é um tipo de serviço LoadBalancer que permite o acesso do tráfego do cliente ao nosso controlador Ingress.


O LoadBalancer tem acesso à rede pública e à rede interna do Kubernetes e, no L7, direciona o tráfego para o controlador do Ingress.


 apiVersion: v1 kind: Service metadata: labels: run: haproxy-ingress name: haproxy-ingress namespace: test spec: type: LoadBalancer ports: - name: http port: 80 protocol: TCP targetPort: 80 - name: https port: 443 protocol: TCP targetPort: 443 - name: stat port: 1936 protocol: TCP targetPort: 1936 selector: run: haproxy-ingress 

Vamos aplicar todos os manifestos HAProxy.


 $ kubectl apply -f haproxy-configmap.yml -f haproxy-deployment.yml -f haproxy-service.yml configmap "haproxy-configmap" created deployment "haproxy-ingress" created service "haproxy-ingress" created 

Quando todos os recursos estiverem em execução, especifique o terminal do LoadBalancer.


 $ kubectl -n test get svc haproxy-ingress -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR haproxy-ingress LoadBalancer 100.67.194.186 a694abcdefghi11e8bc3b0af2eb5c5d8-806901662.us-east-1.elb.amazonaws.com 80:31788/TCP,443:32274/TCP,1936:32157/TCP 2m run=ingress 

Mapear DNS para URL do aplicativo


Assim que especificarmos o ponto de extremidade ELB para o serviço Ingress, precisaremos mapear o DNS do serviço e o URL da solicitação (por exemplo, test-rails-app.com ).


Implementação do Ingress


A parte mais difícil está por trás, é hora de configurar as regras do Ingress e do Path.


Precisamos das seguintes regras.


As solicitações para https://test-rails-app.com serão processadas pelo serviço de test-production-web .


As solicitações para https://test-rails-app.com/websocket serão processadas pelo serviço test-production-websocket .


As solicitações para https://test-rails-app.com/api serão processadas pelo serviço test-production-api .


Vamos criar um manifesto do Ingress com todas essas regras.


 --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress namespace: test spec: tls: - hosts: - test-rails-app.com secretName: tls-certificate rules: - host: test-rails-app.com http: paths: - path: / backend: serviceName: test-production-web servicePort: 80 - path: /api backend: serviceName: test-production-api servicePort: 80 - path: /websocket backend: serviceName: test-production-websocket servicePort: 80 

No caso de alterações na configuração, temos anotações para os recursos do Ingress .


Como esperado, por padrão, nosso tráfego para / roteado para o test-production-web , /api para test-production-api e /websocket para test-production-websocket .


Precisávamos de roteamento baseado em caminho e terminação SSL no L7 no Kubernetes, e a implementação do Ingress resolveu esse problema.

Source: https://habr.com/ru/post/pt424789/


All Articles