打通本地与K8s集群的微服务开发工具:NocalHost

1. 背景

(不关心背景的直接看第三部分)
应用服务上云以后,我们的开发周期,显著拉长了。意味着我们验证功能、排查错误的周期边长了。
通常一个服务开发必须经历:开发、CR、合入代码、流水线构建、镜像发布、k8s负载更新。这几个阶段,才能在k8s远端环境内生效。
又或者,我们的微服务数量比较多的时候,开发一个需求,本地需要起多个依赖容器与微服务应用,非常繁琐,影响我们开发效率,以及在验收阶段定位问题的速度。
为了解决这个痛点,我们曾经做过一些尝试:

  • Vs Code server: 远端的Pod当做一个服务器,暴露一个界面给用户。把代码编译、运行放在pod里。可以无缝使用K8s资源。
    • 优点:借助pvc做到持久化,稳定性良好
    • 缺点:Java开发普遍更习惯使用jetbrains系列的工具,不适应vs code
  • Jetbrains Gateway:本地client和pod内的服务端通过ssh连接。本地ide编辑,gateway负责同步,后端ide服务构建和运行
    • 优点:对于java开发友好,无需改变使用习惯,比vscode server多一些小功能,例如基于ssh通道,自动端口转发
    • 缺点:稳定性差,一个是本地客户端作为编辑展示端莫名也占用很高的资源,其次连接延迟很大,用户体验很差

此外,还有Vs Code的ssh远程开发,模式和gateway类似,主要的缺点还是大部分java开发的使用习惯上,更偏向于idea。

2. NocalHost简介

经过调研,NocalHost工具可以显著的解决我们的痛点。
NocalHost的优势在于:

  • Ide无关,他的工作原理是基于代码同步的,所以本地用什么开发,完全没影响
  • 支持远端运行,无缝复用k8s集群资源
  • 适合各种场景的需要,由简单到复杂,依次是:
    • 在本地代理k8s远端服务:不用同步代码,只是本地服务单向访问k8s服务,基于port-forwad命令,但是增加了管理界面和稳定性保障
    • 开发模式:在远端pod里同步、执行本地代码,代替原有的服务,是我们使用最多的开发场景
    • 开发模式-mesh场景:默认开发模式的缺点在于不适合多人协作的场景,因为直接用本地代码替换了远端服务。mesh模式更强大,它借助envoy的sidecar,实际是新建了一个工作负载,但是你可以通过配置规则,更改流量路径,将特定流量导入到你的开发pod里。比如service A 背后是deployment AA,你借助mesh模式,实际新建了一个AA-backup,不会侵入原有的AA。这时候我们指定http header里:service字段=AA的访问原有服务,service字段=backup的访问back服务。这样就可以在不影响原有功能的前提下,灵活调试我们自己的代码。
  • 理念更先进:和vs code server、jetbrains gateway相比,可能部分情况下,能达到类似的效果,但是背后的工作机制是有代差的。
    • 前两者其实是把pod当服务器来用。
    • nocalhost是基于云原生的思路,和k8s无缝衔接。
    • 这两者的区别就是:nocalhost可以轻易的实现仅转发端口以及mesh功能,而vs code server和jb gateway永远无法轻易做到这两点。因为nh的视角是集群维度的。

但是nocalhost也不是没有缺点,这类方案的缺点是:
本地文件的监听服务会占用开发机器的负载

nocalhost官网地址:https://nocalhost.dev/
github: https://github.com/nocalhost/nocalhost
不过他们的官方文档写的不是很『开箱即用』,尤其对于不怎么了解k8s的开发,会吃力一些。

3. NocalHost使用

经过一些摸索和学习后,总结了下面的使用模式:

3.1 安装NocalHost

Idea用户直接在插件市场搜索安装。
Vs Code用户也一样。
file
插件安装成功后,可以在右侧边栏看到:
file

3.2 导入kube config

nocalhost与k8s集群交互,依赖kube config。
所以我们需要指定文件的路径:
file
添加成功后,nocalhost边栏可以看到集群信息:
file

3.3 选择目标负载,启动开发模式

file
如果deployment里有多个container,选择你关心的那个:
file
开发模式,需要绑定本地目录,我们手动指定:
file
例如这里,我选择我们的微服务代码库:
file

3.4 设置开发模式

file
出现这个弹窗后,我们可以直接进入开发模式,但是为了方便后续的开发,建议提前设置一下。
首先,删除无关的container:
file

设置镜像:

这里结合我们的java技术栈选型,基于官方提供的构建脚本(https://github.com/nocalhost/dev-container),
我准备好了jdk17+maven 3.8.5+gradle7.6.1的默认镜像,内置了一些常用开发工具。
nocalhost官方提供了常用语言的默认镜像,不满足需求的话,建议像我一样自行构建适合自己的镜像。
厂内镜像:
registry.baidubce.com/crowdtest-dev/nh-java:17
厂外可以基于这个Dockerfile,替换到https://github.com/nocalhost/dev-container下java/Dockerfile文件自行构建:

ARG JAVA_VERSION=17

FROM openjdk:${JAVA_VERSION}-jdk-buster

RUN sed -i 's/httpredir.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list

ARG ROOTHOME=/Users/root

RUN mkdir -p $ROOTHOME
ENV HOME=$ROOTHOME

RUN apt-get update --allow-unauthenticated \
    && apt install --allow-unauthenticated --force-yes -y ca-certificates curl \
           build-essential gcc g++ \
           tzdata zip unzip vim wget \
           git openssh-client zsh bash net-tools tmux sudo wget \
    #
    # Clean up
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*
    COPY ./apache-maven-3.8.5-bin.tar.gz ./
RUN tar -zxvf apache-maven-3.8.5-bin.tar.gz -C /usr/local/lib/ \
    && rm apache-maven-3.8.5-bin.tar.gz

ENV PATH="/usr/local/lib/apache-maven-3.8.1/bin:${PATH}"

# 安装 Gradle
ENV GRADLE_VERSION=7.6.1

# 下载并解压 Gradle
RUN wget -q https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip -P /tmp \
    && unzip -q /tmp/gradle-${GRADLE_VERSION}-bin.zip -d /opt \
    && rm /tmp/gradle-${GRADLE_VERSION}-bin.zip

# 设置 Gradle 环境变量
ENV GRADLE_HOME=/opt/gradle-${GRADLE_VERSION}
ENV PATH=${GRADLE_HOME}/bin:${PATH}

# update timezone
ENV TZ Asia/Shanghai
RUN cp /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# Mark zsh as default shell
RUN chsh -s /usr/bin/zsh

# RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v1.1.1/zsh-in-docker.sh)" -- \
COPY ./zsh/zsh-in-docker.sh /tmp
RUN chmod +x /tmp/zsh-in-docker.sh && \
    /tmp/zsh-in-docker.sh \
    -a 'SPACESHIP_PROMPT_ADD_NEWLINE="false"' \
    -a 'SPACESHIP_PROMPT_SEPARATE_LINE="false"' \
    -p git \
    -p https://github.com/zsh-users/zsh-autosuggestions \
    -p https://github.com/zsh-users/zsh-completions \
    -p https://github.com/zsh-users/zsh-history-substring-search \
    -p https://github.com/zsh-users/zsh-syntax-highlighting \
    -p 'history-substring-search' \
    -a 'bindkey "\$terminfo[kcuu1]" history-substring-search-up' \
    -a 'bindkey "\$terminfo[kcud1]" history-substring-search-down'

# Copy local config to p10k zsh
COPY ./zsh/.p10k.zsh $ROOTHOME/
COPY ./zsh/.tmux.conf $ROOTHOME/

RUN mkdir $ROOTHOME/.m2
COPY ./mvn/settings.xml $ROOTHOME/.m2/

ENTRYPOINT [ "/bin/zsh" ]
CMD ["-l"]

file
设置Run And Debug:
file
为了每次都能执行最新的代码 ,我们给一个先编译再运行的command:
格式大概类似这样:
{gradle build xxxx};{java -jar xxx …}
给一个例子:
RUN

gradle mark-service:mark-service-verify:build -x test; java -Djava.security.egd=file:/dev/./urandom -Dfile.encoding=UTF-8 -XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=50.0 --add-opens java.base/java.lang.reflect=ALL-UNNAMED -jar ./micro-service/micro-service-verify/build/libs/micro-service-verify.jar`

DEBUG:

gradle micro-service:micro-service-verify:build -x test;  java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -Djava.security.egd=file:/dev/./urandom -Dfile.encoding=UTF-8 -XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=50.0 --add-opens java.base/java.lang.reflect=ALL-UNNAMED -jar ./micro-service/micro-service-verify/build/libs/micro-service-verify.jar

java的jvm调试端口,默认是5005。
最后大概这样:
file

点击apply:
file

3.5 重新发起dev mode

file
然后等待。
file
允许。
file
漏斗标志时,代码正在处理中,需要再等一下。
变成小锤子就代表成功进入开发模式了:
file

3.6 文件同步

file

下边栏这里可以看到同步进度,我们只有在同步完成后,才可以运行或者debug。
nocalhost还提供了文件同步的进度管理界面:
file

3.7 端口转发

右键负载
file

选择port-forward
添加9000:80,这个意思是本地9000端口的请求会转发到pod的80端口
file
file

3.8 运行和调试

文件同步完成后,我们可以右键remote run或者remote debug。
这个时候会调用我们之前设置的命令。
访问本地的9000端口,就能访问到远端服务了。
同时,调试模式下的断点信息,也会同步到远端。

4. 视频版

【NocalHost基本使用】 https://www.bilibili.com/video/BV14o4y1J7C6/?share_source=copy_web&vd_source=075478aea8acb41082ed3f293b937a17


已发布

分类

, , , ,

来自

标签:

评论

发表回复