前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2024程序员容器化上云之旅-第2集-Ubuntu-WSL2-Windows11版:接近深洞

2024程序员容器化上云之旅-第2集-Ubuntu-WSL2-Windows11版:接近深洞

原创
作者头像
程序员吾真本
发布2024-02-22 11:29:31
3791
发布2024-02-22 11:29:31
举报

故事梗概

Java程序员马意浓在互联网公司维护老旧电商后台系统。

渴望学习新技术的他在工作中无缘Docker。

他开始自学Vue3并使用SpringBoot3完成了一个前后端分离的Web应用系统,并打算将其用Docker容器化后用K8s上云。

3 挑选工具

马意浓画好架构图后,就开始为这次技能升级之旅挑选工具。

他深知,Docker诞生于Linux操作系统。而部署容器的生产环境,也通常使用Linux。

为了使本地测试更接近生产环境,他需要在本地配备一套Linux系统,以测试所开发的容器化应用程序。

此外,他常用的编程和办公软件都在Windows上运行。

?因此,WSL2成为了唯一能同时兼顾Windows上的编程和办公软件,以及在Linux上部署容器化应用的解决方案。

他有一台旧Windows 10笔记本电脑。i5的4核CPU。

原本的内存是8GB,后来在维修中心将其扩展到了20GB。

但跑起程序来,还是感觉慢。

他于是设法搞到了一台新一点的Windows 11迷你主机。i7的14核CPU。内存32GB。

新机器使用起来感觉流畅多了。如图1。

图1 Windows 11新机器使用起来感觉流畅多了
图1 Windows 11新机器使用起来感觉流畅多了

Windows11主机选好后,他发现上面自带WSL2。于是他在PowerShell终端窗口,运行命令wsl --install。系统默认安装了Ubuntu。

他运行命令wsl --list --verbose,列出WSL2目前所以已经安装好的Linux的发行版distro。

屏幕显示有一个名为Ubuntu的distro已经安装好,并且VERSION是2。这表明它是WSL2版本。

他在PowerShell窗口,用鼠标点击右上方加号右边的下箭头,调出一个下拉菜单。

他从中选择了Ubuntu。这样就打开了刚刚安装好的Ubuntu的终端窗口。

接着他输入Ubuntu系统版本号查询命令cat /etc/issue。系统显示22.04.3 LTS

这表示他已经拥有了一套用于部署容器化应用的Linux系统。

他在learning.oreilly.com图书订阅网站上,找来Stuart Leeks在2020年出版的Windows Subsystem for Linux 2 (WSL 2) Tips, Tricks, and Techniques一书,快速了解了WSL2的用法。

读了这本书,他领悟到,WSL2中的Ubuntu,不仅可以当做部署容器化应用的测试环境,更可以配合Windows 11上现成的vscode等开发工具,成为一个开发环境。

喜欢开源软件的马意浓,很喜欢在Ubuntu上进行编程。

WSL2上的Ubuntu,让他能感受到孙悟空找到如意金箍棒的快意。他的精神为之一振。

他现在需要在Ubuntu上安装git、jdk、node.js和npm这些工具。

?比较直接的安装方法,就是分别去这些工具的官网,下载最新的安装包,进行安装。

但马意浓知道,这种方法,只能爽一时。

当遇到一些老旧项目,需要在同一工具新旧多个版本间切换时,就比较麻烦。

比如jdk从2017年之后,版本升级就从过去的几年一次,变成半年一次。

马意浓在工作中所维护的老旧系统,前一阵IT部门好不容易从jdk6升级到jdk8。

他之前那台Windows 10的笔记本电脑,就是从Oracle官网上找到jdk8的下载页面,下载安装包,然后解压并安装的。

既然要技能升级,jdk就要使用2024年主流版本17。

如果还是使用老办法,那就得再从官网下载并安装jdk17。

然后手工在SettingsEnvironment Variables里修改JAVA_HOMEPATH环境变量,以便从jdk11切换到jdk17。

要是想再回到老旧项目的jdk8,又得做一通手工环境变量修改。这太麻烦了。

该如何应对上面的场景?马意浓决定先问一下AIGC。

?AIGC回答:【可以使用包管理器来解决开发工具版本切换的问题。】

【在Ubuntu操作系统中,可以用apt来安装git。】

【用sdkman来安装不同版本的jdk。】

【用nvm来安装不同版本的node.js和npm】

3.1 挑好PowerShell

马意浓知道,编程离不开命令行工具。

他打开Windows 11默认自带的命令行工具PowerShell,并在里面敲入命令$PSVersionTable.PSVersion

屏幕显示PowerShell的版本是5.1。

他去网上搜了一下,得知现在的PowerShell的最新版本是7.4.1。

他想,既然PowerShell是微软制作的,那么在Windows 11的Microsoft Store里应该能找到最新版本。

?果然,他在Microsoft Store里成功安装了7.4.1版的PowerShell。

3.2 挑好git

他打算用apt来安装最新版的git。

不过在安装之前,他想看看Ubuntu系统是否已经自带了git。

他运行命令git --version,屏幕显示git version 2.34.1

他上网查了一下目前最新的git版本,是2024年2月13日发布的版本2.34.2。

他想试试能否通过apt将git升级到2.34.2。

在升级之前,他先运行命令sudo apt update,让apt了解目前所能提供的最新的包的版本号。

然后他运行命令sudo apt install --only-upgrade git,来试图升级git。

屏幕提示git is already the newest version (1:2.34.1-1ubuntu1.10)。

看来apt的包库还没更新到2.34.2最新版。不过2.34.1也足够好了。

3.3 克隆代码

?有了git,马意浓于是进入到一个保存源代码的文件夹,运行git clone命令。

他把之前写好的前后端分离的Shopping List Web App源代码,从github的wubin28账号下的名为shopping-list-web-app-2024-for-wsl2的代码库,克隆到本地电脑。

(因为众所周知的原因,本系列文章不会包含外部恋街。如你需要可以在留言区留言。)

克隆好代码后,马意浓在Ubuntu终端窗口里,进入项目文件夹shoppling-list-web-app-2024-for-wsl2。

3.4 git命令别名

?马意浓进入项目文件夹后,首先在自己账号的home文件夹中,创建.gitconfig文件,设置了git命令的别名。

这样一来,像git status这样经常使用且很长的命令,就可以短别名git st来代替。

使用git的体验一下子好了许多。

3.5 命令行提示显示分支名

马意浓还想让Ubuntu终端窗口提示符,显示目前所check out的git分支名称,以免搞错分支。

?他上网查了一下,发现安装zsh以及oh my zsh工具,并且使用名为agnoster的theme,就能很好地解决这个问题。

很快,他就安装好了zsh和oh my zsh,并在~/.zshrc文件里配置好了agnoster。

但命令行提示本应出现小图标的地方,却出现了乱码。

他又上网查了一下。最后根据ohmyzsh官网Themes页面中agnoster这个theme的提示,安装了字体,但还是乱码。

他又上网一通搜索。最后发现,需要在PowerShell窗口的设置里,把Ubuntu终端的外观中的字体,改成字体名中带有Powerline字样的字体。

他试了一下,终于乱码消失,命令行提示符出现了醒目的当前分支名和小箭头!

3.6 浏览源文件

?马意浓运行文件查看命令,简单回顾了这个项目文件夹中3个子文件夹中的文件。

back-end文件夹存放了后端代码、后端Dockerfile和其他配置文件。

front-end文件夹存放了前端代码、前端Dockerfile和其他配置文件。

通过读Docker书,马意浓了解到,Dockerfile是一种配置文件,用于把源代码构建为docker image,以便以容器化的方式进行部署。

infrastructure文件夹存放了运行docker compose和k8s的配置文件docker-compose.yml

3.7 用sdkman安装jdk 17以便在本地进行后端app构建

马意浓现在需要用jdk构建后端app了。

?他在网上找到了sdkman的安装方法。

安装好后,他运行命令sdk?version验证一下。

屏幕显示sdkman的版本是5.18.2。

他又运行命令sdk list java,查看sdkman可供安装的jdk版本。

他选择了Temurin jdk 17.0.10,因为这个版本是基于OpenJDK开发的。

?他运行命令sdk install java 17.0.10-tem,安装Temurin jdk 17。

屏幕显示正在下载。由于网速较慢,马意浓着实等了一会儿。

等安装完毕后,他运行命令ll ~/.sdkman/candidates/java,查看sdkman所安装的jdk版本。

屏幕显示已经安装了jdk 17.0.10-tem。

马意浓又运行命令sdk use java 17.0.10-tem,选择刚刚安装的jdk17,作为这个终端窗口的jdk版本。

然后他运行命令sdk current java,验证当前正在使用的jdk确实是版本17。

最后,他运行命令java -version,以验证jdk17是否正常工作。

屏幕显示jdk版本是openjdk version "17.0.10" 2024-01-16。

3.8 用nvm安装node.js和npm以便在本地进行前端app构建

马意浓通过上网搜索了解到,nvm是Node Version Manager的简称。

它是Mac和Linux上管理多个 Node.js 版本的工具。

他在github的nvm-sh账号下,找到了nvm的安装方法。

安装完后,他重新打开一个Ubuntu终端窗口,运行命令nvm -v,验证nvm的版本。

屏幕显示nvm的版本是0.39.7。

?接着,马意浓运行命令nvm ls-remote --lts,列出可供安装的所有长期支持版的nvm的版本。

然后,他运行命令nvm install --lts,安装最新的长期支持版的node.js和npm。

屏幕显示,node.js v20.11.1正在下载。很快,屏幕显示与之配套的npm v10.2.4也已经安装成功。

马意浓运行命令nvm use 20.11.1,以使用刚刚安装好的node.js和npm。

接着,他又运行命令node -v,以验证前端工具node.js的版本。

屏幕显示node.js版本是v20.11.1。

他又运行命令npm -v,以验证前端构建工具npm的版本。

屏幕显示npm版本是10.2.4。

4 接近深洞

开发前后端分离Web应用的主要开发工具都准备好了。

?马意浓的下一个目标,就是在wsl2的Ubuntu本地Gradle和npm的开发环境里,成功运行前后端分离的shopping list web app。

目前,前端app和后端app的源代码都已经克隆下来了。

但要把代码跑起来,需要把postgres数据库和pgadmin管理工具运行起来。

因为购物清单数据都需要存储到数据库中。

而且后端app在使用gradle进行构建时,会运行自动化测试,需要访问数据库。

如果在后端app构建时找不到postgres数据库,那么gradle构建会失败。

?马意浓觉得现在可以用docker容器来运行数据库及其管理工具,从而迈出容器化的第一步。

4.1 安装docker desktop以用容器方式运行postgres数据库及其管理工具

马意浓之前在工作中,如需要使用数据库及其管理工具,都是从官网下载安装包进行安装。

但就和安装jdk类似,这种安装方法使得将来卸载或升级数据库时,会非常麻烦。

他从资料中了解到,在容器化的时代,如果想使用数据库及其管理工具,完全可以从Docker hub上,下载对应的docker image文件。

之后在本地电脑用简单的一行命令,就能启动相应的容器,来使用数据库及其管理工具。

将来卸载或升级,也是运行一行命令的事儿。方便至极。

之前马意浓还担心,容器里跑数据库,要是关闭或删除容器,那数据不就丢了。

?后来通过读Nigel Poulton的Doker书,他了解到,可以为数据库容器设置一个位于本地硬盘中的volume,以便保存持久化的数据。

只要不删除这个volume,数据库容器关闭后再启动,仍然能够获取之前的数据。

4.1.1 安装docker desktop

?马意浓在docker的官网上,找到了docker desktop for Windows的安装方法。

他按图索骥,安装好。再根据提示重启电脑,并用自己的docker hub账号登录docker desktop。

他看到所安装的docker?desktop for windows版本是v4.27.2(137060)。

他从那本WSL2的书里了解到,在docker desktop的settings里,如果设置了允许docker与WSL2 Ubuntu distro集成,那么在Ubuntu终端窗口里,就能使用docker命令。

他在docker desktop的settings里,点击Resources,再点击WSL integration,把Ubuntu的开关打开,并点击Apply & restart。

然后,他回到Ubuntu终端窗口,运行命令docker system info,屏幕出现了大量docker系统的信息。

这表明他现在能在WSL2 Ubuntu终端窗口里使用docker命令了。

4.1.2 用容器方式运行postgres数据库及其管理工具

马意浓在Ubuntu终端窗口里,进入项目文件夹,再运行命令进入infrastructure子文件夹。

?然后再运行命令docker compose up postgres pgadmin,启动postgres数据库和pgadmin管理工具。

他知道,这个命令会读取infrastructure文件夹下面的docker-compose.yml文件。并根据其中有关postgres和pgadmin服务的配置信息,启动这两个服务。

等到屏幕显示两个容器都启动了,他切换到docker desktop界面,看到两个容器都启动后的界面。如图2。

图2 在docker desktop中启动postgres和pgadmin容器
图2 在docker desktop中启动postgres和pgadmin容器

马意浓用鼠标点击docker desktop中pgadmin-1那一行的5050:80链接,打开了一个浏览器。

数据库管理界面出现在眼前。

他在数据库管理界面中,输入了登录信息。

用户名和密码都是admin@gmail.com

他知道这个用户名和密码,是在docker-compose.yml文件中的pdadmin服务中设置好的。

他用鼠标右击数据库管理界面中的Servers,然后点击Register,点击Server…。

?这时出现了数据库服务器的Register界面。

他在General里的Name里,填写了数据库服务器名shopping-list-web-app

他又点击Connection页签,在Host name/address里,填写了数据库服务器主机名postgres

他确认了一下,Port已经填好了5432,Maintenance database已经填好了postgres

他把Username改成了postgres。把Password设置为postgres。将Save password设置为允许。

确认一切都填好了,他点击了Save按钮。

刚刚创建的shopping-list-web-app数据库服务器就出现在眼前。

就能在数据库出现问题时查看数据库里的数据,如图3。

图3 刚刚创建的shopping-list-web-app数据库服务器就出现在眼前
图3 刚刚创建的shopping-list-web-app数据库服务器就出现在眼前

4.2 在本地Gradle开发环境启动后端app

数据库已经运行起来了。马意浓开始在本地Gradle开发环境启动后端app。

他在Ubuntu终端窗口,按快捷键Ctrl+Shift+5,打开一个新的Ubuntu终端窗口。然后进入项目文件夹。

之后他进入后端app代码文件夹back-end

?他运行命令java -version,确认当前jdk版本设置为17。

然后运行命令./gradlew bootRun启动后端app。

屏幕滚过一些提示信息,最后出现了Started ShoppingListApplication提示。

马意浓知道,这表示后端app已经成功启动了。

他还想继续验证这一点。于是他打开浏览器,在地址栏输入localhost:8081/swagger-ui.html

一个OpenAPI definition页面出现在眼前。

马意浓知道,这是后端app的api接口定义信息。这表示后端app已经启动了。

在这个api接口定义界面,他是可以通过鼠标点击,来访问后端app获取数据的。

马意浓用鼠标点开GET /api/v1/shopping-items接口,然后点击Try it out按钮。

再点击Execute按钮,这时在下面Response body里,返回了[]空记录。

他知道,这是正常的。因为现在数据库里还没有任何数据。如图4。

图4 在OpenAPI definition页面里访问GET /api/v1/shopping-items接口
图4 在OpenAPI definition页面里访问GET /api/v1/shopping-items接口

4.3 在本地npm开发环境启动前端app

他又按快捷键打开一个新的Ubuntu终端窗口,进入项目文件夹,然后进入前端app代码文件夹front-end

他又运行命令nvm use 20.11.1。屏幕显示当前node.js版本已经设置为v20.11.1,npm版本已经设置为v10.2.4。

然后他运行命令npm install,以便安装package.json文件所设置的依赖库。

他等到屏幕显示命令执行完毕后,知道此时依赖库已经安装好了。

他接着运行命令npm run dev,启动前端app。

很快,他看到屏幕显示Local: <hxxp://localhost:5173/

他按住Ctrl键,然后用鼠标点击屏幕上的5173链接。

这样就打开了一个Chrome浏览器网页,显示了Shopping List Web App前端页面。

终于,他在本地电脑,用docker容器运行了数据库,并成功启动了后端app和前端app

马意浓很兴奋。

他在前端页面的Item输入框中,输入了a banana,点击Add按钮。

但所输入的购物项,却没有按照预期出现在下面的列表中。

他预感到一定是出问题了。

他于是在浏览器中,按快捷键Ctrl+Shift+I,打开Developer tools窗口,想看看出错日志。

他点击Console页签,一行红色背景的CORS出错信息映入眼帘。

Access to XMLHttpRequest at 'hxxp://localhost:8081/api/v1/shopping-items' from origin 'hxxp://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

他之前在写完后端app和前端app代码后,进行联调时,遇到过这样的CORS问题。

当时他按照网上查到的几个解决方案,这里试试,那里试试,就莫名其妙地就解决了。

但那时光顾着高兴,忘了记笔记了。

在没有笔记的情况下,要想回忆当时是如何解决的,几乎是不可能了。

?【未完待续


?后面连载内容大纲先睹为快

?5 历经磨难

5.1 在用本地Gradle/npm开发环境自测时面临前端无法访问后端的CORS问题的挑战

5.2 清理现场

?6 夺取宝剑

6.1 在本地docker compose里的软件架构

6.2 免费注册Docker hub账号以便推送docker image为部署k8s做准备

6.3 构建后端docker image并推送到docker hub

6.4 构建前端docker image并推送到docker hub

6.5 在本地docker compose里运行shopping list web app

6.6 清理现场

?7 上云之路

7.1 打开docker desktop kubernetes让kubectl能正常工作

?8 复活重生

8.1 在k8s云集群中运行shopping list web app时如何配置前端app在k8s云集群中的对外域名和端口号以解决CORS问题

8.2 在全绽园的帮助下为前端app配置ingress后解决了这个问题

8.3 在k8s云集群中的软件架构

8.4 如何新增k8s的deployment、service和ingress的配置文件,以便使用kubectl命令将ingress和postgres、shopping-list-api和shopping-list-front-end这3个微服务部署到k8s上

8.5 构建后端docker image并推送到docker hub

8.6 构建前端docker image并推送到docker hub

8.7 在k8s云集群上配置postgres、shopping-list-api和shopping-list-front-end三个微服务和ingress并运行

8.8 清理现场

?9 取经归来

当最终把前后端分离的web应用成功部署到Docker Desktop k8s云集群上,并能顺利使用后,马意浓把整个容器化和上云之旅,写成系列文章,分享给其他程序员。


?你能否跟着马意浓一步步做下来?在阅读中有任何疑问,欢迎在留言区留言。我会一一回复

??如果喜欢本文,那么点赞留言,并转发给身边有需要的朋友,就是对我的最大支持???。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 故事梗概
  • 3 挑选工具
    • 3.1 挑好PowerShell
      • 3.2 挑好git
        • 3.3 克隆代码
          • 3.4 git命令别名
            • 3.5 命令行提示显示分支名
              • 3.6 浏览源文件
                • 3.7 用sdkman安装jdk 17以便在本地进行后端app构建
                  • 3.8 用nvm安装node.js和npm以便在本地进行前端app构建
                  • 4 接近深洞
                    • 4.1 安装docker desktop以用容器方式运行postgres数据库及其管理工具
                      • 4.1.1 安装docker desktop
                      • 4.1.2 用容器方式运行postgres数据库及其管理工具
                    • 4.2 在本地Gradle开发环境启动后端app
                      • 4.3 在本地npm开发环境启动前端app
                      相关产品与服务
                      容器服务
                      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档


                      http://www.vxiaotou.com