Bootstrap

K8S学习笔记-------2.极简易懂的入门示例

1. 准备应用代码

编写Node.js应用代码,并确保它可以在本地运行。

1.1 确保 Node.js 和 npm 已安装

在使用 npm 之前,需要先安装 Node.js。因为 npm 是随 Node.js 一起安装的。你可以通过以下命令检查它们是否已经安装以及查看版本信息:

zgq@docker01:~$ node -v
Command 'node' not found, but can be installed with:
sudo apt install nodejs
zgq@docker01:~$ npm -v
Command 'npm' not found, but can be installed with:
sudo apt install npm

我的机器没有安装npm、node ,以下执行安装操作,(先安装node)
先执行对系统的更新操作

root@docker01:/home/zgq# apt update
root@docker01:/home/zgq# apt upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following upgrades have been deferred due to phasing:
  libunwind8 python3-distupgrade ubuntu-release-upgrader-core
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
zgq@docker01:~$ sudo apt install nodejs
sudo: unable to resolve host docker01: Name or service not known
[sudo] password for zgq: 
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libcares2 libnode109 node-acorn node-busboy node-cjs-module-lexer node-undici node-xtend nodejs-doc
Suggested packages:
  npm
The following NEW packages will be installed:
  libcares2 libnode109 node-acorn node-busboy node-cjs-module-lexer node-undici node-xtend nodejs nodejs-doc
0 upgraded, 9 newly installed, 0 to remove and 143 not upgraded.
Need to get 16.1 MB of archives.
After this operation, 70.4 MB of additional disk space will be used.
Do you want to continue? [Y/n] y

再安装npm

root@docker01:/home/zgq# apt install npm
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
npm is already the newest version (9.2.0~ds1-2).
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.

验证版本信息

zgq@docker01:~$ sudo node -v
v18.19.1
zgq@docker01:~$ sudo npm -v
9.2.0

如果显示出版本号,说明已经安装成功。

1.2. 创建项目目录并初始化项目

如果你还没有项目目录,可以创建一个新的目录,并在该目录下初始化一个新的 Node.js 项目。以下是具体操作:

# 创建一个新的项目目录
zgq@docker01:~$ mkdir my-express-app
# 进入项目目录
zgq@docker01:~$ cd my-express-app
# 初始化项目,会生成一个 package.json 文件
zgq@docker01:~/my-express-app$ npm init -y
Wrote to /home/zgq/my-express-app/package.json:
{
  "name": "my-express-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

npm init -y 中的 -y 选项表示使用默认配置快速初始化项目,这样会自动生成一个 package.json 文件,该文件用于记录项目的元数据和依赖信息。

1.3. 安装 Express

  • 项目目录下执行 npm install express 命令:
zgq@docker01:~/my-express-app$ npm install express

added 69 packages, and audited 70 packages in 6s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
  • 执行该命令后,npm 会从 npm 仓库下载 Express 及其所有依赖项,并将它们安装到项目目录下的 node_modules 文件夹中。同时,package.json 文件会更新,添加 Express 作为项目的依赖项,如下所示:
zgq@docker01:~/my-express-app$ cat package.json
{
  "name": "my-express-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.21.2"  // 此版本号可能会根据实际安装情况有所不同,执行npm install 命令后会添加Express作为项目的依赖项
  }
}

1.4 验证安装

  • 安装完成后,你可以创建一个简单的 Express 应用来验证是否安装成功。在项目目录下创建一个名为 app.js 的文件,内容如下:
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, World!');
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

可以使用nano编辑,例如:

zgq@docker01:~/my-express-app$ nano app.js
  • 在终端中运行以下命令启动应用:
zgq@docker01:~/my-express-app$ node app.js
Server is running on port 3000
  • 打开浏览器,访问 http://localhost:3000或者http://your-server-ip:3000,如果看到页面显示 Hello, Kubernetes!,则说明 Express 安装成功并且应用正常运行。
    在这里插入图片描述

2.容器化应用

2.1 准备 Dockerfile

在项目根目录下创建一个 Dockerfile 文件,用于定义如何构建镜像。以下是一个简单的 Node.js 应用的 Dockerfile 示例:

# 使用官方 Node.js 镜像作为基础镜像
FROM node: current-slim

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json
COPY package*.json ./

# 安装依赖
RUN npm install

# 复制项目文件
COPY . .

# 暴露端口(假设应用运行在 3000 端口)
EXPOSE 3000

# 启动应用
CMD ["npm", "start"]

2.2 构建镜像

  • 包含 Dockerfile 的目录下运行以下命令:

注意:命令行最某尾的" . " : 表示 Dockerfile 和构建上下文位于当前目录。

ubuntu@ip-172-31-89-208:~/zgq-kube/App$ sudo docker build -t zhuguoqiang999/node-app:1.0 .
[+] Building 9.4s (11/11) FINISHED                                                                                       docker:default
 => [internal] load build definition from Dockerfile                                                                               0.0s
 => => transferring dockerfile: 223B                                                                                               0.0s
 => [internal] load metadata for docker.io/library/node:current-slim                                                               0.5s
 => [auth] library/node:pull token for registry-1.docker.io                                                                        0.0s
 => [internal] load .dockerignore                                                                                                  0.0s
 => => transferring context: 170B                                                                                                  0.0s
 => [1/5] FROM docker.io/library/node:current-slim@sha256:278dc9616f605d5de4304fb19bf245ec1fd5569fddf2c7ea611f6e7262de98b5         3.4s
 => => resolve docker.io/library/node:current-slim@sha256:278dc9616f605d5de4304fb19bf245ec1fd5569fddf2c7ea611f6e7262de98b5         0.0s
 => => extracting sha256:60eeb4400e1d51b1953b4b40591ad79190856f512afd10df0dcb13d184cf49c7                                          0.0s
 => => sha256:278dc9616f605d5de4304fb19bf245ec1fd5569fddf2c7ea611f6e7262de98b5 6.49kB / 6.49kB                                     0.0s
 => => sha256:9673e806eca4f9b3d32a0b8259e68c766d062136e3ea8e98bcffc440010a37b1 1.93kB / 1.93kB                                     0.0s
 => => sha256:3632793bb481bbf2c572029478b0141d66cbdc590dd32d4a708aa04605f8529d 6.54kB / 6.54kB                                     0.0s
 => => sha256:60eeb4400e1d51b1953b4b40591ad79190856f512afd10df0dcb13d184cf49c7 3.31kB / 3.31kB                                     0.1s
 => => sha256:ce755d7cf7f5964170ef8f511ba3de78ca52a5e4871dc9f467d05d47ae846059 49.81MB / 49.81MB                                   0.8s
 => => sha256:dc6c34e52d5c07b4fa00771ccd49191e4f3d6685ad6ab5cb7b53370bbc18a4f0 1.71MB / 1.71MB                                     0.2s
 => => sha256:ed279290f28c8b2682ebe25022d1df670b7c3a1499ab10bf6a00439647154c06 448B / 448B                                         0.2s
 => => extracting sha256:ce755d7cf7f5964170ef8f511ba3de78ca52a5e4871dc9f467d05d47ae846059                                          2.2s
 => => extracting sha256:dc6c34e52d5c07b4fa00771ccd49191e4f3d6685ad6ab5cb7b53370bbc18a4f0                                          0.1s
 => => extracting sha256:ed279290f28c8b2682ebe25022d1df670b7c3a1499ab10bf6a00439647154c06                                          0.0s
 => [internal] load build context                                                                                                  0.0s
 => => transferring context: 1.13kB                                                                                                0.0s
 => [2/5] WORKDIR /src                                                                                                             0.1s
 => [3/5] COPY package*.json ./                                                                                                    0.0s
 => [4/5] RUN npm install                                                                                                          4.9s
 => [5/5] COPY . .                                                                                                                 0.0s
 => exporting to image                                                                                                             0.3s
 => => exporting layers                                                                                                            0.3s
 => => writing image sha256:02a5d7d363c3ab6e6d6b0a92cf9580d6ca1ac01b9cfb71e0ec2ac7f60086ee6c                                       0.0s
 => => naming to docker.io/zhuguoqiang999/node-app:1.0                                                                             0.0s
  • 查看生成的镜像。构建完成后,可以使用以下命令查看本地镜像:在这里插入图片描述
  • 运行容器。使用以下命令运行容器:
ubuntu@ip-172-31-89-208:~/zgq-kube/App$ sudo docker run -p 3000:3000 zhuguoqiang999/node-app:1.0
Server is running on port 3000
  • 测试应用。
    打开浏览器或使用 curl 访问 http://localhost:3000,检查应用是否正常运行。

需要重新开启另外一个终端连接服务器。

ubuntu@ip-172-31-89-208:~$ curl http://localhost:3000
Hello, Kubernetes! @Zhuguoqiang 2025.2.4  2937425@qq.
  • 推送镜像到 Docker Hub
    如果你想将镜像推送到 Docker Hub,可以按照以下步骤操作:
    1.登录 Docker Hub:
ubuntu@ip-172-31-89-208:~$ sudo docker login
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores

Login Succeeded
  2.推送镜像:
ubuntu@ip-172-31-89-208:~$ sudo docker  push zhuguoqiang999/node-app:1.0
The push refers to repository [docker.io/zhuguoqiang999/node-app]
922d2f65e7aa: Pushed
289c1592db1b: Pushed
324187b0ba8b: Pushed
6cd6185f60c1: Pushed
10608948e461: Mounted from library/node
a1789e7ed79e: Mounted from library/node
dd75864d0f98: Mounted from library/node
5b7299b84b0c: Mounted from library/node
f5fe472da253: Mounted from zhuguoqiang999/qsk-book
1.0: digest: sha256:548a79a5fea6b61180156f53f7d54846ab333d87edf7fed8b8c740ada9421fa1 size: 2198
  • 在Docker hub上查看镜像
    在这里插入图片描述

注意事项:

Dockerfile 路径:确保 Dockerfile 文件位于当前目录(.),或者指定正确的路径。
镜像名称:zhuguoqiang999/node-app 中的 zhuguoqiang999 必须是你的 Docker Hub 用户名,否则推送时会失败。
标签管理:建议为镜像添加明确的标签(如 zhuguoqiang999/node-app:1.0),而不是默认的 latest。

  • 示例项目结构
    假设你的项目结构如下:运行 docker build -t zhuguoqiang999/node-app . 后,Docker 会基于 Dockerfile 构建镜像。
ubuntu@ip-172-31-89-208:~$ tree zgq-kube
zgq-kube
└── App
    ├── Dockerfile
    ├── app.js
    └── package.json

2 directories, 3 files

3.编写K8s配置文件

创建 Deployment

将以下YAML 文件保存为 node-deployment.yaml,

# node-deployment.yaml
apiVersion: apps/v1
kind: Deployment # 表明这是 Kubernetes Deployment
metadata:
  name: node-deployment # Deployment 的名称
spec:
  replicas: 3 # 希望运行的 Pod 副本数量
  selector:
    matchLabels:
      app: node-app # 选择具有这些标签的 Pod
  template:
    metadata:
      labels:
        app: node-app # 模板中创建的 Pod 的标签
    spec:
      containers:
      - name: node-container # 容器的名称
        image: zhuguoqiang999/node-app:1.0 # 使用的 Docker 镜像版本
        ports:
        - containerPort: 3000 # 容器内部监听的端口


运行以下命令创建和查看 Deployment、POD:

# 先测试node-deployment.yaml语法
zgq@k8s-node1:~/zgq-kube$ kubectl apply --dry-run='client' -f node-deployment.yaml
deployment.apps/node-deployment configured (dry run)
# 执行创建deployment
zgq@k8s-node1:~/zgq-kube$ kubectl apply  -f node-deployment.yaml
deployment.apps/node-deployment created
# 查看创建的deployment
zgq@k8s-node1:~/zgq-kube$ kubectl get deployment |grep node-deployment
node-deployment       3/3     3            3           12m
# 查看创建的pods
zgq@k8s-node1:~/zgq-kube$ kubectl get pods |grep node-deployment
node-deployment-5c574c5cdb-6pwrq      1/1     Running   0          13m
node-deployment-5c574c5cdb-7hkm8      1/1     Running   0          13m
node-deployment-5c574c5cdb-qzm9v      1/1     Running   0          13m

创建 Service

为了让外部访问 Node.js 应用,需要创建一个 Service。创建一个 node-service.yaml 文件:

# node-service.yaml
apiVersion: v1
kind: Service # 表明这是 Kubernetes Service
metadata:
  name: node-service # Service 的全局唯一名称
spec:
  type: NodePort # 类型为 NodePort
  ports:
    - port: 80 # Service 提供服务的端口号
      targetPort: 3000 # 目标 Pod 上容器监听的端口号
      nodePort: 30008 # 暴露在节点上的端口号(可选,如果不指定会自动分配)
  selector:
    app: node-app # Service 对应的 Pod 拥有这里定义的标签

4.部署到K8s集群

应用Deployment

运行以下命令创建和查看 Deployment、POD:

# 先测试node-deployment.yaml语法
zgq@k8s-node1:~/zgq-kube$ kubectl apply --dry-run='client' -f node-deployment.yaml
deployment.apps/node-deployment configured (dry run)
# 执行创建deployment
zgq@k8s-node1:~/zgq-kube$ kubectl apply  -f node-deployment.yaml
deployment.apps/node-deployment created
# 查看创建的deployment
zgq@k8s-node1:~/zgq-kube$ kubectl get deployment |grep node-deployment
node-deployment       3/3     3            3           12m
# 查看创建的pods
zgq@k8s-node1:~/zgq-kube$ kubectl get pods |grep node-deployment
node-deployment-5c574c5cdb-6pwrq      1/1     Running   0          13m
node-deployment-5c574c5cdb-7hkm8      1/1     Running   0          13m
node-deployment-5c574c5cdb-qzm9v      1/1     Running   0          13m

应用Service

应用 Service 配置:

zgq@k8s-node1:~/zgq-kube$ kubectl apply --dry-run='client' -f node-service.yaml
service/node-service created (dry run)
zgq@k8s-node1:~/zgq-kube$ kubectl apply  -f node-service.yaml
service/node-service created
zgq@k8s-node1:~/zgq-kube$ kubectl get svc
NAME                  TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
hello-node            LoadBalancer   10.50.57.188    <pending>     8080:30856/TCP   7d17h
kubernetes            ClusterIP      10.50.0.1       <none>        443/TCP          34d
kubernetes-bootcamp   NodePort       10.50.28.53     <none>        8080:30707/TCP   7d16h
mysql                 ClusterIP      10.50.174.42    <none>        3306/TCP         45h
myweb                 NodePort       10.50.154.206   <none>        80:30001/TCP     42h
node-service          NodePort       10.50.72.149    <none>        80:30008/TCP     10s
svc-local             NodePort       10.50.187.62    <none>        8080:31111/TCP   3d1h

获取Service的NodePort端口:

zgq@k8s-node1:~/zgq-kube$ kubectl describe svc node-service
Name:                     node-service
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=node-app
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.50.72.149
IPs:                      10.50.72.149
Port:                     <unset>  80/TCP
TargetPort:               3000/TCP
NodePort:                 <unset>  30008/TCP
Endpoints:                10.60.36.83:3000,10.60.169.147:3000,10.60.36.82:3000
Session Affinity:         None
External Traffic Policy:  Cluster
Internal Traffic Policy:  Cluster
Events:                   <none>

5.验证应用是否正常运行

使用Minikube或其他K8s集群,找到节点IP并访问:

minikube ip

然后在浏览器中访问:http://<node-ip>:<node-port>

应该看到 “Hello Kubernetes!”。
在这里插入图片描述

;