O objetivo final do desenvolvimento de aplicativos é, obviamente, expor aplicativos na Internet. Para um desenvolvedor, o Kubernetes simplifica esse processo até certo ponto ao fornecer o controlador Ingress como mecanismo de roteamento de solicitações para o aplicativo. Mas nem tudo é tão self-service quanto você provavelmente gostaria: você ainda precisa de um registro no Sistema de Nomes de Domínio (DNS) para mapear o nome de domínio do aplicativo para o endereço IP do controlador Ingress e um certificado TLS para proteger conexões usando HTTPS. Na maioria das organizações, você não é o proprietário do DNS ou do TLS e, portanto, precisa coordenar com o grupo operacional (ou grupos!) que o possui.
As coisas não são necessariamente mais fáceis para os operadores. Na maioria das organizações, a necessidade de atualizar registros DNS é rara o suficiente para que os procedimentos – tanto as regras de negócios quanto as etapas técnicas reais – tendam a ser esparsos ou inexistentes. Isso significa que quando você precisa adicionar um registro DNS, primeiro precisa encontrar a documentação, perguntar a um colega ou (na pior das hipóteses) descobrir. Você também precisa garantir que está em conformidade com todas as regras de segurança corporativa e certificar-se de que a entrada esteja marcada corretamente para os firewalls.
Felizmente, existe uma maneira de facilitar a vida tanto dos desenvolvedores quanto dos operadores. Nesta postagem, mostramos como os operadores podem configurar uma implantação do Kubernetes para permitir o autoatendimento para desenvolvedores atualizarem registros DNS e gerarem certificados TLS em um ambiente Kubernetes. Ao construir a infraestrutura com antecedência, você pode garantir que todos os requisitos comerciais e técnicos necessários sejam atendidos.
Com a solução implementada, tudo o que um desenvolvedor precisa fazer para expor um aplicativo à Internet é criar um controlador Ingress seguindo um modelo fornecido que inclui um nome de domínio totalmente qualificado (FQDN) dentro de um domínio gerenciado pela instalação do Kubernetes. O Kubernetes usa o modelo para alocar um endereço IP para o controlador Ingress, criar o registro DNS A
para mapear o FQDN para o endereço IP e gerar certificados TLS para o FQDN e adicioná-los ao controlador Ingress. A limpeza é igualmente fácil: quando o Ingress é removido, os registros DNS são limpos.
A solução aproveita as seguintes tecnologias (fornecemos instruções de instalação e configuração abaixo):
Antes de configurar a solução, você precisa:
LoadBalancer
). A solução usa Linode, mas outros provedores de nuvem também funcionam.kubectl
como interface de linha de comando para Kubernetes.Também presumimos que você tenha um conhecimento básico do Kubernetes (como aplicar um manifesto, usar um gráfico Helm e emitir comandos kubectl
para visualizar a saída e solucionar problemas). Entender os conceitos básicos do Let's Encrypt é útil, mas não obrigatório; para uma visão geral, consulte nosso blog . Você também não precisa saber como o cert-manager funciona, mas se estiver interessado em como ele (e os certificados em geral) funcionam com o NGINX Ingress Controller, veja minha postagem recente, Automatizando o gerenciamento de certificados em um ambiente Kubernetes .
Testamos a solução no macOS e no Linux. Não testamos no Windows Subsystem for Linux versão 2 (WSL2), mas não prevemos problemas.
Observação: A solução foi concebida como uma prova de conceito de amostra e não para uso em produção. Em particular, ele não incorpora todas as melhores práticas de operação e segurança. Para obter informações sobre esses tópicos, consulte a documentação do cert-manager e do ExternalDNS .
Siga as etapas nestas seções para implantar a solução:
Clone o repositório do NGINX Ingress Controller:
$ git clone https://github.com/nginxinc/kubernetes-ingress.gitCloning into 'kubernetes-ingress'...
remote: Enumerating objects: 45176, done.
remote: Counting objects: 100% (373/373), done.
remote: Compressing objects: 100% (274/274), done.
remote: Total 45176 (delta 173), reused 219 (delta 79), pack-reused 44803
Receiving objects: 100% (45176/45176), 60.45 MiB | 26.81 MiB/s, done.
Resolving deltas: 100% (26592/26592), done.
Verifique se você consegue se conectar ao cluster do Kubernetes.
$ kubectl cluster-infoKubernetes control plane is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443
KubeDNS is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Usando o Helm, implante o NGINX Ingress Controller. Observe que estamos adicionando três opções de configuração não padronizadas :
controller.enableCustomResources
– Instruímos o Helm a instalar as definições de recursos personalizados (CRDs) que permitem criar os recursos personalizados NGINX VirtualServer e VirtualServerRoute.controller.enableCertManager
– Configura o NGINX Ingress Controller para se comunicar com os componentes do cert-manager .controller.enableExternalDNS
– Configura o Ingress Controller para se comunicar com componentes ExternalDNS.$ helm install nginx-kic nginx-stable/nginx-ingress --namespace nginx-ingress --set controller.enableCustomResources=true --create-namespace --set controller.enableCertManager=true --set controller.enableExternalDNS=trueNAME: nginx-kic
LAST DEPLOYED: Day Mon DD hh:mm:ss YYYY
NAMESPACE: nginx-ingress
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The NGINX Ingress Controller has been installed.
Verifique se o NGINX Ingress Controller está em execução e anote o valor no campo EXTERNAL-IP
– é o endereço IP do NGINX Ingress Controller (aqui, www.xxx.yyy.zzz
). A saída é distribuída em duas linhas para maior legibilidade.
$ kubectl get services --namespace nginx-ingressNAME TYPE CLUSTER-IP ...
nginx-kic-nginx-ingress LoadBalancer 10.128.152.88 ...
... EXTERNAL-IP PORT(S) AGE
... www.xxx.yyy.zzz 80:32457/TCP,443:31971/TCP 3h8m
Na solução, o cert-manager usa o tipo de desafio DNS-01 ao obter um certificado TLS, o que exige que o token da API do Cloudflare seja fornecido durante a criação do recurso ClusterIssuer . Na solução, o token da API é fornecido como um Kubernetes Secret .
Usando o Helm, implante o cert-manager :
$ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1 --set installCRDs=trueNAME: cert-manager
LAST DEPLOYED: Day Mon DD hh:mm:ss YYYY
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.9.1 has been deployed successfully!
Implante o token da API do Cloudflare como um segredo do Kubernetes, substituindo-o por <seu-token-API>
:
$ kubectl apply -f - <<EOFapiVersion: v1
kind: Secret
metadata:
name: Cloudflare-api-token-secret
namespace: cert-manager
type: Opaque
stringData:
api-token: "<your-API-token>"
EOF
secret/Cloudflare-api-token-secret created
Crie um objeto ClusterIssuer, especificando Cloudflare-api-token-secret
(definido na etapa anterior) como o local para recuperar o token. Se desejar, você pode substituir example-issuer
no campo metadata.name
(e example-issuer-account-key
no campo spec.acme.privateKeySecretRef.name
) por um nome diferente.
$ kubectl apply -f - <<EOFapiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: example-issuer
namespace: cert-manager
spec:
acme:
email: example@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: example-issuer-account-key
solvers:
- dns01:
Cloudflare:
apiTokenSecretRef:
name: Cloudflare-api-token-secret
key: api-token
EOF
clusterissuer.cert-manager.io/example-issuer created
Verifique se o ClusterIssuer está implantado e pronto (o valor no campo READY
é True
).
$ kubectl get clusterissuerNAME READY AGE
example-issuer True 3h9m
Assim como o cert-manager, o projeto ExternalDNS requer um token de API do Cloudflare para gerenciar o DNS. O mesmo token pode ser usado para ambos os projetos, mas isso não é obrigatório.
Crie os CRDs do ExternalDNS para o NGINX Ingress Controller para permitir a integração entre os projetos.
$ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yamlcustomresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org created
Crie o serviço DNS externo ( external-dns
). Como o manifesto é bastante longo, aqui o dividimos em duas partes. A primeira parte configura contas, funções e permissões:
external-dns
para gerenciar todas as operações de gravação e atualização para gerenciar o DNS.external-dns
) que define as permissões necessárias.$ kubectl apply -f - <<EOFapiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: ["externaldns.nginx.org"]
resources: ["dnsendpoints"]
verbs: ["get","watch","list"]
- apiGroups: ["externaldns.nginx.org"]
resources: ["dnsendpoints/status"]
verbs: ["update"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: default
EOF
serviceaccount/external-dns created
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
A segunda parte do manifesto cria a implantação do ExternalDNS:
domain-filter
como example.com
.CF_API_TOKEN
para seu token de API do Cloudflare. Para <seu-token-API>
, substitua o token real ou um Segredo contendo o token. No último caso, você também precisa projetar o Secret no contêiner usando uma variável de ambiente.FREE_TIER
como "true"
(apropriado, a menos que você tenha uma assinatura paga do Cloudflare).$ kubectl apply -f - <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: k8s.gcr.io/external-dns/external-dns:v0.12.0
args:
- --source=service
- --source=ingress
- --source=crd
- --crd-source-apiversion=externaldns.nginx.org/v1
- --crd-source-kind=DNSEndpoint
- --domain-filter=example.com
- --provider=Cloudflare
env:
- name: CF_API_TOKEN
value: "<your-API-token>"
- name: FREE_TIER
value: "true"
EOF
serviceaccount/external-dns created
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
deployment.apps/external-dns created
Use o aplicativo de exemplo padrão do NGINX Ingress Controller chamado Cafe para fins de teste.
Implante o aplicativo Cafe.
$ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yamldeployment.apps/coffee created
service/coffee-svc created
deployment.apps/tea created
service/tea-svc created
Implante o NGINX Ingress Controller para o aplicativo Cafe. Observe as seguintes configurações:
tipo: VirtualServer
– Estamos usando o recurso personalizado NGINX VirtualServer, não o recurso padrão do Kubernetes Ingress.spec.host
– Substitua cafe.example.com
pelo nome do host que você está implantando. O host deve estar dentro do domínio que está sendo gerenciado com ExternalDNS.spec.tls.cert-manager.cluster-issuer
– Se você estiver usando os valores especificados nesta postagem, este é example-issuer
. Se necessário, substitua o nome escolhido na Etapa 3 de Implantar cert‑manager .spec.externalDNS.enable
– O valor true
informa ao ExternalDNS para criar um registro DNS A.
Observe que o tempo que leva para essa etapa ser concluída depende muito do provedor de DNS, pois o Kubernetes está interagindo com a API de DNS do provedor.
$ kubectl apply -f - <<EOFapiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: cafe
spec:
host: cafe.example.com
tls:
secret: cafe-secret
cert-manager:
cluster-issuer: example-issuer
externalDNS:
enable: true
upstreams:
- name: tea
service: tea-svc
port: 80
- name: coffee
service: coffee-svc
port: 80
routes:
- path: /tea
action:
pass: tea
- path: /coffee
action:
pass: coffee
EOF
virtualserver.k8s.nginx.org/cafe created
Verifique o registro DNS A
– em particular se no bloco ANSWER
SECTION
o FQDN (aqui, cafe.example.com
) está mapeado para o endereço IP correto ( www.xxx.yyy.zzz
).
$ dig cafe.example.com
; <<>> DiG 9.10.6 <<>> cafe.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22633
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;cafe.example.com. IN A
;; ANSWER SECTION:
cafe.example.com. 279 IN A www.xxx.yyy.zzz
;; Query time: 1 msec
;; SERVER: 2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359#53(2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359)
;; WHEN: Day Mon DD hh:mm:ss TZ YYYY
;; MSG SIZE rcvd: 67
Verifique se o certificado é válido (o valor no campo READY
é True
).
$ kubectl get certificatesNAME READY SECRET AGE
cafe-secret True cafe-secret 8m51s
Verifique se você consegue acessar o aplicativo.
$ curl https://cafe.example.com/coffeeServer address: 10.2.2.4:8080
Server name: coffee-7c86d7d67c-lsfs6
Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
URI: /coffee
Request ID: 91077575f19e6e735a91b9d06e9684cd
$ curl https://cafe.example.com/tea
Server address: 10.2.2.5:8080
Server name: tea-5c457db9-ztpns
Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
URI: /tea
Request ID: 2164c245a495d22c11e900aa0103b00f
Muita coisa acontece nos bastidores quando a solução é implementada. O diagrama mostra o que acontece quando um desenvolvedor implanta o NGINX Ingress Controller com um recurso personalizado do NGINX VirtualServer. Observe que alguns detalhes operacionais são omitidos.
A
A
no DNSDada a complexidade do Kubernetes e dos componentes que estamos usando, é difícil fornecer um guia de solução de problemas abrangente. Dito isso, há algumas sugestões básicas para ajudar você a determinar o problema.
kubectl
get
e kubectl
describe
para validar a configuração de objetos implantados.kubectl
registros
<componente>
comando para visualizar arquivos de log para os vários componentes implantados.Se você ainda estiver tendo problemas, entre em contato conosco no Slack da Comunidade NGINX e peça ajuda! Temos uma comunidade vibrante e estamos sempre felizes em resolver problemas.
Para experimentar o NGINX Ingress Controller baseado no NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso .
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."