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用户也一样。
插件安装成功后,可以在右侧边栏看到:
3.2 导入kube config
nocalhost与k8s集群交互,依赖kube config。
所以我们需要指定文件的路径:
添加成功后,nocalhost边栏可以看到集群信息:
3.3 选择目标负载,启动开发模式
如果deployment里有多个container,选择你关心的那个:
开发模式,需要绑定本地目录,我们手动指定:
例如这里,我选择我们的微服务代码库:
3.4 设置开发模式
出现这个弹窗后,我们可以直接进入开发模式,但是为了方便后续的开发,建议提前设置一下。
首先,删除无关的container:
设置镜像:
这里结合我们的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"]
设置Run And Debug:
为了每次都能执行最新的代码 ,我们给一个先编译再运行的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。
最后大概这样:
点击apply:
3.5 重新发起dev mode
然后等待。
允许。
漏斗标志时,代码正在处理中,需要再等一下。
变成小锤子就代表成功进入开发模式了:
3.6 文件同步
下边栏这里可以看到同步进度,我们只有在同步完成后,才可以运行或者debug。
nocalhost还提供了文件同步的进度管理界面:
3.7 端口转发
右键负载
选择port-forward
添加9000:80,这个意思是本地9000端口的请求会转发到pod的80端口
3.8 运行和调试
文件同步完成后,我们可以右键remote run或者remote debug。
这个时候会调用我们之前设置的命令。
访问本地的9000端口,就能访问到远端服务了。
同时,调试模式下的断点信息,也会同步到远端。
4. 视频版
【NocalHost基本使用】 https://www.bilibili.com/video/BV14o4y1J7C6/?share_source=copy_web&vd_source=075478aea8acb41082ed3f293b937a17
发表回复
要发表评论,您必须先登录。