云原生学习

最近看了一些云安全的面经,发现技术面的相关问题我很多都答不上来,前段时间公有云的学习也莫名其妙的没有下文了,特别是有了ai之后独立思考的能力渐渐缺失,很难独立去完成靶场了,索性换个方向先简单了解一下,从公有云转到云原生上

学习线路:

  1. 基石:容器化(Docker)
    理解镜像与容器的关系,学会编写 Dockerfile,把应用打包成标准镜像。这是云原生一切应用的“交付物”。
  2. 核心:Kubernetes 编排
    掌握 Pod、Deployment、Service 等核心对象。这是你需要投入最多时间的阶段。Minikube 的作用就在于此,让你能实际部署、观察、调试这些资源。
  3. 进阶:微服务与流量治理
    学习服务发现、配置中心(如 Nacos)以及服务网格(如 Istio)的基础概念。
  4. 效率:DevOps 与 CI/CD
    理解如何通过 GitLab CI 或 ArgoCD 等工具,实现代码从提交到 K8s 集群的自动化部署。

docker

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

docker 常用基本命令

docker pull 镜像名:版本号 下载镜像

docker images 查看本地下载的镜像

docker ps 查看正在运行的容器

docker run -it 镜像名:版本号 运行容器

docker exec -it 容器id sh 进入容器

docker rm -f 容器id 删除容器

docker rmi 镜像id 删除镜像

docker tag 镜像id 镜像名:版本号 给镜像打标签

docker build -t 镜像名:版本号 . 构建镜像

docker commit -a="作者" -m="说明" 容器id 镜像名:版本号 提交容器变更到镜像

docker history 镜像名:版本号 查看镜像的构建历史

dockerfire

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM ubuntu:18.04  # 基础镜像

RUN apt-get update # 更新软件源
RUN apt-get install -y vim # 安装vimecho

RUN apt-get update && apt-get install -y curl # (推荐)

COPY ./a /a # 将当前目录下的a文件复制到镜像的/a目录下

ADD ./b /b # 将当前目录下的b文件复制到镜像的/b目录下 (远端url、压缩包)

WORKDIR /a # 设置工作目录为/a

CMD ["tail", "-f", "/dev/null"] # 设置容器启动时执行的命令

ENTRYPOINT ["/manager"] # 设置容器启动时执行的命令

k8s学习

之前在学aws的时候的学习经费还有好多没有用,再不用就浪费了,再开一台vps来学云原生

学习k8s肯定需要自己上手实操一下,这里推荐minikube,它能在你的本地电脑上快速拉起一个单节点 K8s 集群,让你零成本地练习所有核心操作,且官方教程都是基于它编写,生态中的大多数入门示例都能直接跑通。

安装

minikube start | minikube 中文

以linux为例

1
2
curl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64

启动集群

1
minikube start --driver=docker --v=7

image-20261014093322103

这样就是下载启动成功了

验证一下

1
minikube kubectl -- get pods -A

image-20261014093448672

易用配置

1
vim ./.bashrc

添加再末尾

1
2
alias kubectl="minikube kubectl --"
source <(kubectl completion bash)

这是将minikube kubectl --这一长坨命令简化成kubectl,方便操作,且模拟环境更加完善

-- 是 Unix/Linux 的通用约定,表示**“选项到此为止,后面的都是位置参数(要传给子命令的内容)”**。

也就是说如果没有--之后的命令get pods -A就会被根命令minikube解析,而这个命令是属于kubectl的,这样解析肯定会报错

删除集群

1
minikube delete

k8s相关概念

Pod

Pod是Kubernetes中最小的可部署计算单元,您可以在其中创建和管理它。

Pod的共享上下文包括一组Linux命名空间、cgroups以及其他可能的隔离机制。在Pod的上下文中,各个应用程序可以进一步实现子隔离。

Pod类似于一组容器,这些容器共享命名空间和文件系统卷。

在Kubernetes集群中,Pod主要有两种使用方式:

  1. 运行单个容器的Pod。这种“一个Pod一个容器”的模式是最常见的Kubernetes用例。此时,您可以将Pod视为单个容器的包装层,Kubernetes直接管理Pod而非容器本身。
  2. 运行多个需要协同工作的容器的Pod。Pod可以封装由多个紧密耦合的容器组成的应用程序,这些容器需要共享资源。
Namespace 管什么 Pod 内是否共享
network 网络接口、IP、端口 共享(同一 IP,端口不能冲突)
mount 文件系统挂载点 默认隔离(各有各的根文件系统)
pid 进程 ID 默认隔离(可配置共享)
ipc 进程间通信(信号量、共享内存) 共享
uts 主机名、域名 共享(同一 hostname)
user 用户和 UID 映射 默认隔离
cgroup cgroup 视图 共享
time 系统时钟偏移 默认隔离
  • network:Pod 内容器共用 IP 和端口空间,所以 localhost 能互相访问,但同一端口只能被一个容器占用。
  • ipc:可以用 System V IPC 或 POSIX 消息队列通信。
  • uts:共享主机名,hostname 命令看到的是同一个。

1280X1280

每个 Pod 启动时,kubelet 会先拉起一个极小的容器,镜像叫 pause(infra container)(通常几十 KB 到几百 KB)。它只做一件事:

1
2
3
4
// pause 容器的核心逻辑(简化)
for (;;) {
pause(); // 一直睡眠,什么都不干
}

它的作用就是占住并持有 Pod 级别的 namespace:

  • 创建 network namespace,并配置好 Pod 的 IP
  • 创建 ipc、uts namespace
  • 作为 cgroup 的挂载点

然后,Pod 里的所有业务容器在启动时,通过 --net=container:<pause容器ID> 这类方式,加入到 pause 容器已经创建好的 namespace 里。

也就是说

Pod的共享namespace 由pause容器创建并持有,业务容器都是”加入者”

集群(Cluster)

Kubernetes 集群是由一组节点(Node)组成的集合,用于运行容器化应用程序。集群由控制平面(Control Plane)和工作节点(Worker Node)组成。

  • 控制平面:负责管理集群的状态和调度任务,包括 API Server、Scheduler、Controller Manager 和 etcd 等组件。
  • 工作节点:运行实际的容器化应用程序,每个节点包含 kubelet、kube-proxy 和容器运行时(如 Docker 或 containerd)。

K8s概念总览图-略

节点(Node)

节点是 Kubernetes 集群中的工作单元,可以是物理机或虚拟机。节点分为两种类型:

  • Master 节点:运行控制平面组件,负责集群管理。
  • Worker 节点:运行应用程序容器,由控制平面调度。

命名空间(Namespace)

命名空间是 Kubernetes 中用于资源隔离的逻辑分区。通过命名空间,可以将集群资源划分为多个虚拟集群,适用于多团队或多环境场景。

  • 默认命名空间:default,未指定命名空间的资源默认属于此命名空间。
  • 系统命名空间:如 kube-system,用于运行 Kubernetes 系统组件。
Kubernetes(k8s)基础概念介绍

Pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
namespace: default
labels:
app: my-app
tier: backend
version: "1.0"
annotations:
description: "This is a sample application pod"
maintainer: "devops-team"
spec:
# 重启策略
restartPolicy: Always

# 容器定义
containers:
- name: main-container
image: nginx
imagePullPolicy: IfNotPresent

# 容器启动命令
command: ["nginx"]
args: ["-g", "daemon off;"]

# 端口配置
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP

# 环境变量
env:
- name: ENVIRONMENT
value: "production"
- name: LOG_LEVEL
value: "info"

# 资源限制
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"

# 健康检查
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

#livenessProbe:
#exec:
#command:
#- cat
#- /tmp/healthy

readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 1

以上是一个比较全面的Pod模板

关于apiVersion

K8s 把所有 API 分组,每组有版本。不同资源属于不同的组:

资源 apiVersion
Pod、Service、ConfigMap v1(核心组)
Deployment、DaemonSet apps/v1
Job、CronJob batch/v1
Ingress networking.k8s.io/v1
Role、RoleBinding rbac.authorization.k8s.io/v1

apiVersion 写错,K8s 就找不到这个资源类型,直接报错。

此处v1 这种只有版本、没有组名的,是 K8s 最早期、最基础的资源,叫核心组:

包含:

  • Pod
  • Service
  • ConfigMap
  • Secret
  • Namespace
  • Node
  • PersistentVolume
  • PersistentVolumeClaim

特点:最基础、最稳定,从 K8s 诞生就有。

元数据(metadata)

1
2
3
4
5
name: btop251
namespace: default
uid: ac987043-77fb-49e6-ae26-2b1a337462ae
resourceVersion: "6287"
creationTimestamp: "2026-10-14T06:46:26Z"
  • uid:Pod 的全局唯一 ID,即使删了重建同名 Pod,uid 也不同
  • resourceVersion:版本号,K8s 内部用乐观锁,每次修改递增
  • namespace:default, YAML 没写,默认落到 default
  • lables:可以理解为标签,将对应的资源分类,方便快速查找,有字数上限
  • description:描述,给人看的,让你知道这玩意是干嘛用的,没有字数上限

spec(期望状态)

这是核心部分。你希望对应资源的状态,没写的属性会使用默认值,注意这个是期望而不是命令

比如说

1
2
spec:
replicas: 3

表示的是我希望这里有三个pod,而不是给我创建三个pod,她的判定标准是最终的结果是否为三个pod,多退少补,而不是实际的执行过程创建三个pod

status (实际状态)

这部分是 K8s 写的,你只读。 它反映 Pod 的真实情况。先不管

实践

在实际情况中可以通过先创建一个yaml文件来来此一个pod资源

1
vim pod.yaml
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1	 # 用哪个 API 版本
kind: Pod # 是什么资源
metadata: # 元数据(名字、标签、命名空间)
name: btop251
spec: # 期望状态(这个资源长什么样)
containers:
- name: btop251
image: alpine
command: ["/bin/sh"]
stdin: true #对应docker -i保持容器的stdin开启(非必须
tty: true #对应docker -t开启伪终端(非必须

创建好之后可以通过

1
kubectl apply -f pod.yaml

or

1
kubectl create -f pod.yaml

来创建资源,apply不仅可以创建资源,也可以用于修改资源,所以在实际情况下往往都是直接通过该命令,很少使用create

通过以下命令查看这个pod的相关配置信息

1
kubectl get po btop251 -oyaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
apiVersion: v1
kind: Pod
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"btop251","namespace":"default"},"spec":{"containers":[{"command":["/bin/sh"],"image":"alpine","name":"btop251","stdin":true,"tty":true}]}}
creationTimestamp: "2026-10-14T06:46:26Z"
generation: 1
name: btop251
namespace: default
resourceVersion: "6287"
uid: ac987043-77fb-49e6-ae26-2b1a337462ae
spec:
containers:
- command:
- /bin/sh
image: alpine
imagePullPolicy: Always
name: btop251
resources: {}
stdin: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
tty: true
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-46vw5
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: minikube-m02
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: kube-api-access-46vw5
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2026-10-14T06:46:26Z"
observedGeneration: 1
status: "True"
type: PodReadyToStartContainers
- lastProbeTime: null
lastTransitionTime: "2026-10-14T06:46:26Z"
observedGeneration: 1
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2026-10-14T06:46:30Z"
observedGeneration: 1
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2026-10-14T06:46:30Z"
observedGeneration: 1
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2026-10-14T06:46:26Z"
observedGeneration: 1
status: "True"
type: PodScheduled
containerStatuses:
- containerID: containerd://7ce52c74c4aac9c2a5b95701e7ca540ffb8545e42110d5c221aa6529cb9633a4
image: docker.io/library/alpine:latest
imageID: docker.io/library/alpine@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6
lastState: {}
name: btop251
ready: true
resources: {}
restartCount: 0
started: true
state:
running:
startedAt: "2026-10-14T06:46:30Z"
user:
linux:
gid: 0
supplementalGroups:
- 0
- 1
- 2
- 3
- 4
- 6
- 10
- 11
- 20
- 26
- 27
uid: 0
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-46vw5
readOnly: true
recursiveReadOnly: Disabled
hostIP: 192.168.49.3
hostIPs:
- ip: 192.168.49.3
observedGeneration: 1
phase: Running
podIP: 10.244.1.4
podIPs:
- ip: 10.244.1.4
qosClass: BestEffort
resources: {}
startTime: "2026-10-14T06:46:26Z"

删除资源

1
kubectl delete pod btop251

or 通过yaml来删除

1
kubectl delete -f pod.yaml

节点调度

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl explain pod.spec.nodeSelector
KIND: Pod
VERSION: v1

FIELD: nodeSelector <map[string]string>


DESCRIPTION:
NodeSelector is a selector which must be true for the pod to fit on a node.
Selector which must match a node's labels for the pod to be scheduled on
that node. More info:
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/

先创建三个node节点,因为创建节点时第一个节点为控制节点有一个taint(污点),普通 Pod 没有对应的 toleration(容忍),就不会被调度上去。所以需要用两个普通节点来做实践

一开始我直接通过

1
kubectl start --driver=docker -n 3

想直接创建三个节点,但是忘记了上一次事件的时候创建的节点没有删除于是触发报错

image-20261014214402481

已经创建的资源,某些属性是“不可变”的,想改只能删了重建,或者用专门的“增量”命令。

类似于上面的通过create来创建pod节点,如果想要修改数量或者属性只能通过apply,这个apply可以当作是修改状态,而create只能用于创建

1
kubectl node add

image-20261014214804047

没问题了

首先要知道每个node对应的资源是不一样的,有些node上会安排gpu算了来跑机器学习,有些

先创建一个带有labels的pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
name: btop251
spec:
nodeSelector:
gpuNode: "true"
#distype: ssd
containers:
- name: btop251
image: alpine
command: ["/bin/sh"]
stdin: true
tty: true

注意这里的gpuNode的vaule是”true”,因为在给lables的时候对应的vaule往往是string格式,默认会给出单引号,但是想true,false这些特殊字符,如果不打上双引号会当作布尔类型的字符来处理

1
kubectl apply -f pod.yaml
1
2
3
$ kubectl get po
NAME READY STATUS RESTARTS AGE
btop251 0/1 Pending 0 7s

注意到状态STATUS为pending,这是一种常见的报错,原因是在创建pod是找不到gpuNode为true的节点,所以创建被挂起而没有跑起来,需要我们给一个节点打上对应的标签

1
2
3
4
$ kubectl label node minikube-m03 gpuNode=true
$ kubectl get po
NAME READY STATUS RESTARTS AGE
btop251 1/1 Running 0 8m38s

删除label

1
kubectl label node minikube-m03 gpuNode-

Contents