
Cada vez mais nos perguntam sobre o desenvolvimento de microsserviços no Kubernetes. Os desenvolvedores, especialmente as linguagens interpretadas, desejam corrigir rapidamente o código em seu IDE favorito e sem esperar pela compilação / implantação para ver o resultado - simplesmente pressionando F5. E quando se tratava do aplicativo monolítico, bastava elevar localmente o banco de dados e o servidor da Web (no Docker, VirtualBox ...), após o qual - aproveite imediatamente o desenvolvimento. Com a serra de monólitos em microsserviços e o advento de Kubernetes, com o surgimento de dependências entre si, as coisas
ficaram um pouco mais complicadas . Quanto mais desses microsserviços, mais problemas. Para aproveitar o desenvolvimento novamente, você precisa levantar mais de um ou dois contêineres do Docker e, às vezes, mais de uma dúzia ... Em geral, tudo isso pode levar muito tempo, porque você também precisa mantê-lo atualizado.
Em momentos diferentes, tentamos soluções diferentes para o problema. E começarei com as soluções alternativas acumuladas ou simplesmente "muletas".
1. Muletas
A maioria dos IDEs tem a capacidade de editar código diretamente no servidor usando FTP / SFTP. Desta forma, é muito óbvio e decidimos imediatamente usá-lo. Sua essência é a seguinte:
- No pod para ambientes de desenvolvimento (dev / review), um contêiner adicional é lançado com acesso via SSH e encaminhando a chave SSH pública do desenvolvedor que confirmará / implementará o aplicativo.
- No estágio init (no contêiner de
prepare-app
), transferimos o código para emptyDir
para ter acesso ao código dos contêineres com o aplicativo e o servidor SSH.

Para uma melhor compreensão da implementação técnica desse esquema, darei fragmentos das configurações YAML envolvidas no Kubernetes.
Configurações
1.1 values.yaml
ssh_pub_key: vasya.pupkin: <ssh public key in base64>
Aqui
vasya.pupkin
é o valor da variável
${GITLAB_USER_LOGIN}
.
1.2 deployment.yaml
... {{ if eq .Values.global.debug "yes" }} volumes: - name: ssh-pub-key secret: defaultMode: 0600 secretName: {{ .Chart.Name }}-ssh-pub-key - name: app-data emptyDir: {} initContainers: - name: prepare-app {{ tuple "backend" . | include "werf_container_image" | indent 8 }} volumeMounts: - name: app-data mountPath: /app-data command: ["bash", "-c", "cp -ar /app/* /app-data/" ] {{ end }} containers: {{ if eq .Values.global.debug "yes" }} - name: ssh image: corbinu/ssh-server volumeMounts: - name: ssh-pub-key readOnly: true mountPath: /root/.ssh/authorized_keys subPath: authorized_keys - name: app-data mountPath: /app ports: - name: ssh containerPort: 22 protocol: TCP {{ end }} - name: backend volumeMounts: {{ if eq .Values.global.debug "yes" }} - name: app-data mountPath: /app {{ end }} command: ["/usr/sbin/php-fpm7.2", "--fpm-config", "/etc/php/7.2/php-fpm.conf", "-F"] ...
1.3 secret.yaml
{{ if eq .Values.global.debug "yes" }} apiVersion: v1 kind: Secret metadata: name: {{ .Chart.Name }}-ssh-pub-key type: Opaque data: authorized_keys: "{{ first (pluck .Values.global.username .Values.ssh_pub_key) }}" {{ end }}
Toque final
Depois disso, resta apenas passar as
variáveis necessárias para o gitlab-ci.yml :
dev: stage: deploy script: - type multiwerf && source <(multiwerf use 1.0 beta) - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose) - werf deploy --namespace ${CI_PROJECT_NAME}-stage --set "global.env=stage" --set "global.git_rev=${CI_COMMIT_SHA}" --set "global.debug=yes" --set "global.username=${GITLAB_USER_LOGIN}" tags: - build
Voila: o desenvolvedor que iniciou a implantação pode se conectar usando o nome do serviço (
já dissemos a você como emitir com segurança o acesso ao cluster) da área de trabalho via SFTP e editar o código sem esperar que ele seja entregue ao cluster.
Esta é uma solução completamente funcional, mas do ponto de vista da implementação, ela tem desvantagens óbvias:
- a necessidade de refinar o gráfico Helm, o que complica ainda mais sua leitura;
- Somente quem implantou o serviço pode usá-lo;
- você precisa se lembrar de sincronizá-lo com o diretório local com o código e confirmar no Git.
2. Telepresença
O projeto de
telepresença é conhecido há bastante tempo, mas seriamente tentá-lo na prática conosco, como se costuma dizer, "não chegou às nossas mãos". No entanto, a demanda fez o seu trabalho e agora temos o prazer de compartilhar experiências que podem ser úteis para os leitores do nosso blog - especialmente porque ainda não havia outros materiais sobre a Telepresença no hub.
Em suma, não foi tão assustador. Todas as ações que requerem execução pelo desenvolvedor, foram colocadas no arquivo de texto do Helm-chart, chamado
NOTES.txt
. Portanto, o desenvolvedor depois de implantar o serviço no Kubernetes vê as instruções para iniciar o ambiente de desenvolvimento local no log de tarefas do GitLab:
!!! , Kubernetes !!! * * * VPN * * kubectl ( https://kubernetes.io/docs/tasks/tools/install-kubectl/ ) * * config- kubectl ( ~/.kube/config) * * telepresence ( https://www.telepresence.io/reference/install ) * * Docker * * reporter https://gitlab.site.com/group/app * * registry / GitLab ( ): ######################################################################### docker login registry.site.com ######################################################################### * ######################################################################### telepresence --namespace {{ .Values.global.env }} --swap-deployment {{ .Chart.Name }}:backend --mount=/tmp/app --docker-run -v `pwd`:/app -v /tmp/app/var/run/secrets:/var/run/secrets -ti registry.site.com/group/app/backend:v8 #########################################################################
Não vamos nos debruçar sobre os passos descritos neste manual ... exceto o último. O que acontece durante o lançamento da Telepresença?
Trabalhar com telepresença
No início (pelo último comando especificado nas instruções acima), definimos:
- namespace (namespace) no qual o microsserviço é iniciado;
- os nomes da implantação e o contêiner que queremos penetrar.
Os argumentos restantes são opcionais. Se nosso serviço interage com a API Kubernetes e
uma ServiceAccount é criada para isso, precisamos montar os certificados / tokens em nossa área de trabalho. Para fazer isso, use a opção
--mount=true
(ou
--mount=/dst_path
), que montará a raiz (/) do contêiner no Kubernetes em nossa área de trabalho. Depois disso, podemos (dependendo do sistema operacional e da maneira como o aplicativo é iniciado) usar as “chaves” do cluster.
Primeiro, considere a opção de inicialização de aplicativo mais versátil - no contêiner Docker. Para fazer isso, use a opção
--docker-run
e monte o diretório com o código no contêiner:
-v `pwd`:/app
Observe que isso implica iniciar no diretório com o projeto. O código do aplicativo será montado no diretório
/app
no contêiner.
Próximo:
-v /tmp/app/var/run/secrets:/var/run/secrets
- para montar o diretório com o certificado / token no contêiner.
Esta opção é finalmente seguida pela imagem na qual o aplicativo será iniciado.
NB : Ao criar uma imagem, você deve especificar
CMD
ou
ENTRYPOINT
!
O que, de fato, acontecerá a seguir?
- No Kubernetes, para a implantação especificada, o número de réplicas será alterado para 0. Em vez disso, uma nova implantação será iniciada - com o contêiner de
backend
substituído. - Na área de trabalho, dois contêineres serão iniciados: o primeiro - com Telepresença (proxy por solicitações de / para o Kubernetes), o segundo - com o aplicativo em desenvolvimento.
- Se exec'nitsya estiver no contêiner com o aplicativo, teremos acesso a todas as variáveis ENV passadas pelo Helm durante a implantação, além de todos os serviços disponíveis. Tudo o que resta é editar o código no seu IDE favorito e aproveitar o resultado.
- No final do trabalho, basta fechar o terminal em que a Telepresença está sendo executada (finalizar a sessão usando Ctrl + C), os contêineres do Docker pararão na área de trabalho e tudo voltará ao seu estado original no Kubernetes. Tudo o que resta é confirmar, emitir o MR e passá-lo para revisar / mesclar / ... (dependendo dos fluxos de trabalho).
Se não queremos executar o aplicativo no contêiner do Docker - por exemplo, desenvolvemos não no PHP, mas no Go e ainda o coletamos localmente - iniciar a Telepresença será ainda mais fácil:
telepresence --namespace {{ .Values.global.env }} --swap-deployment {{ .Chart.Name }}:backend --mount=true
Se o aplicativo acessar a API do Kubernetes, você precisará montar o
diretório com as chaves . Para Linux, existe um utilitário
proot :
proot -b $TELEPRESENCE_ROOT/var/run/secrets/:/var/run/secrets bash
Após iniciar o Telepresence sem a opção
--docker-run
, todas as variáveis de ambiente estarão disponíveis no terminal atual, portanto, é necessário iniciar o aplicativo nele.
NB : Ao usar, por exemplo, PHP, você deve se lembrar de desativar vários op_cache, apc e outros aceleradores para desenvolvimento - caso contrário, editar o código não produzirá o resultado desejado.
Sumário
O desenvolvimento local com o Kubernetes é um problema cuja necessidade de solução está crescendo proporcionalmente à expansão dessa plataforma. Tendo recebido solicitações relevantes dos desenvolvedores (de nossos clientes), começamos a resolvê-los com os primeiros meios disponíveis, que, no entanto, não se provaram a longa distância. Felizmente, isso se tornou óbvio não apenas agora e não apenas para nós; portanto, meios mais adequados já apareceram no mundo, e a Telepresença é a mais famosa delas (a propósito, ainda há um
skaffold do Google). Nossa experiência em seu uso não é tão boa, mas já dá motivos para recomendar "colegas" - experimente!
PS
Outro do ciclo de dicas e truques do K8s: