Kubernetes 提示和技巧:关于本地开发和网真

Kubernetes 提示和技巧:关于本地开发和网真

我们越来越多地询问有关在 Kubernetes 中开发微服务的问题。 开发人员(尤其是解释语言的开发人员)希望在他们最喜欢的 IDE 中快速更正代码并查看结果,而无需等待构建/部署 - 只需按 F5。 当涉及到单体应用程序时,本地安装数据库和 Web 服务器(在 Docker、VirtualBox 中......)就足够了,然后立即享受开发。 随着单体应用被切割成微服务以及 Kubernetes 的到来,随着相互依赖的出现,一切都变得简单起来。 变得有点困难了。 这些微服务越多,问题就越多。 为了再次享受开发的乐趣,你需要启动一两个以上的 Docker 容器,有时甚至是十几个……总的来说,这一切可能会花费相当多的时间,因为它也需要保持最新状态。

在不同的时间我们尝试了不同的解决方案来解决问题。 我将从积累的解决方法或简单的“拐杖”开始。

1.拐杖

大多数 IDE 都能够使用 FTP/SFTP 直接在服务器上编辑代码。 这条路非常明显,我们立即决定使用它。 其本质可归结为以下几点:

  1. 在开发环境(dev/review)的 Pod 中,启动一个具有 SSH 访问权限的附加容器,并转发将提交/部署应用程序的开发人员的公共 SSH 密钥。
  2. 在初始化阶段(在容器内 prepare-app)将代码传输到 emptyDir可以从应用程序容器和 SSH 服务器访问代码。

Kubernetes 提示和技巧:关于本地开发和网真

为了更好地理解该方案的技术实现,我将提供 Kubernetes 中涉及的 YAML 配置的片段。

配置

1.1. 值.yaml

ssh_pub_key:
  vasya.pupkin: <ssh public key in base64> 

这是 vasya.pupkin 是变量的值 ${GITLAB_USER_LOGIN}.

1.2. 部署.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. 秘密.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 }}

最后的触摸

之后剩下的就是转移 所需的 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

瞧:启动部署的开发人员可以通过服务名称进行连接(如何安全地授予对集群的访问权限, 我们已经告诉过)通过 SFTP 从桌面编辑代码,而无需等待代码传送到集群。

这是一个完全可行的解决方案,但从实现的角度来看,它有明显的缺点:

  • 需要细化 Helm 图表,这使得将来难以阅读;
  • 只能由部署该服务的人使用;
  • 你需要记住然后将其与代码同步到本地目录并提交到Git。

2. 网真

项目 网真 已经为人所知很长时间了,但正如他们所说,我们“没有抽出时间在实践中认真尝试。” 然而,需求已经完成了它的工作,现在我们很高兴分享我们的经验,这可能对我们博客的读者有用 - 特别是因为中心上还没有关于网真的其他材料。

总之,一切都变得没有那么可怕了。 我们将需要开发人员执行的所有操作放置在名为的 Helm 图表文本文件中 NOTES.txt。 因此,将服务部署到 Kubernetes 后,开发人员会在 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
#########################################################################

我们不会详细讨论本说明中描述的步骤......除了最后一个步骤。 网真推出期间会发生什么?

使用网真

在启动时(使用上面说明中指定的最后一个命令),我们设置:

  • 微服务运行所在的命名空间;
  • 我们想要渗透的部署和容器的名称。

其余参数是可选的。 如果我们的服务与 Kubernetes API 交互并为 Kubernetes API 交互 服务帐户已创建,我们需要在桌面上安装证书/令牌。 为此,请使用该选项 --mount=true--mount=/dst_path),这会将根目录(/)从 Kubernetes 容器挂载到我们的桌面。 之后,我们可以(取决于操作系统和应用程序的启动方式)使用集群中的“密钥”。

首先,让我们看看运行应用程序的最通用选项 - 在 Docker 容器中。 为此,我们将使用密钥 --docker-run 并将包含代码的目录挂载到容器中: -v `pwd`:/app

请注意,这假设从项目目录运行。 应用程序代码将被挂载到目录中 /app 在一个容器中。

下一篇: -v /tmp/app/var/run/secrets:/var/run/secrets — 将带有证书/令牌的目录挂载到容器中。

该选项最后后面是应用程序将在其中运行的映像。 NB:构建镜像时,必须指定 CMD или ENTRYPOINT!

接下来到底会发生什么?

  • 在 Kubernetes 中,对于指定的 Deployment,副本数将更改为 0。相反,将启动一个新的 Deployment - 使用替代容器 backend.
  • 桌面上将启动 2 个容器:第一个容器包含 Telepresence(它将代理来自/发往 Kubernetes 的请求),第二个容器包含正在开发的应用程序。
  • 如果我们将应用程序执行到容器中,那么部署期间 Helm 传输的所有 ENV 变量都将可供我们使用,并且所有服务也将可用。 剩下的就是在您最喜欢的 IDE 中编辑代码并享受结果。
  • 工作结束时,您只需关闭运行 Telepresence 的终端(使用 Ctrl+C 终止会话)即可 - Docker 容器将停止在桌面上,而在 Kubernetes 中,一切都将返回到其初始状态。 剩下的就是提交、发出 MR 并将其转移到审核/合并/…(取决于您的工作流程)。

如果我们不想在 Docker 容器中运行应用程序 - 例如,我们不是用 PHP 开发,而是用 Go 开发,并且仍然在本地构建它 - 启动 Telepresence 会更简单:

telepresence --namespace {{ .Values.global.env }} --swap-deployment {{ .Chart.Name  }}:backend --mount=true

如果应用程序访问 Kubernetes API,则需要挂载密钥目录 (https://www.telepresence.io/howto/volumes)。 有一个适用于 Linux 的实用程序 ot:

proot -b $TELEPRESENCE_ROOT/var/run/secrets/:/var/run/secrets bash

启动 Telepresence 后没有选项 --docker-run 所有环境变量都将在当前终端中可用,因此必须在其中启动应用程序。

NB:例如,在使用 PHP 时,必须记住禁用各种 op_cache、apc 和其他加速器进行开发 - 否则编辑代码将不会得到所需的结果。

结果

使用 Kubernetes 进行本地开发是一个问题,其解决方案随着该平台的普及而不断增长。 收到开发人员(来自我们的客户)的相关请求后,我们开始使用第一种可用的方法来解决这些问题,但从长远来看,这并没有证明自己的能力。 幸运的是,这不仅现在变得显而易见,而且不仅对我们来说已经变得显而易见,因此世界上已经出现了更合适的手段,而网真就是其中最著名的(顺便说一句,还有 脚手架 来自谷歌)。 我们的使用体验还不是很好,但它已经让我们有理由向我们的“店里同事”推荐它 - 尝试一下!

PS

K8s 提示和技巧系列中的其他内容:

来源: habr.com

添加评论