K8s 基本使用(一)

什么是K8s(kubernetes)?

k8s 是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它最初由 Google 开发,现由 Cloud Native Computing Foundation(CNCF)维护。k8s 的目标是简化应用程序的部署和管理,提供弹性、可扩展、高可用的服务。

k8s 基于容器技术,如 docker,作为应用程序的基本构建块。容器是一种轻量级的虚拟化技术,可以将应用程序及其依赖项打包到一个独立的、可移植的运行环境中。通过使用容器,开发者可以将应用程序与其运行环境隔离开来,并实现快速部署和跨平台运行。

k8s 提供了一套丰富的功能,用于管理容器化应用的生命周期。

K8s 的核心概念

它的核心概念包括:

  • Pod:Pod 是 k8s 管理的最小调度单位,它可以包含一个或多个容器,并共享网络和存储资源。Pod 提供了容器之间的通信和协作。
  • Deployment:Deployment 定义了应用程序的期望状态,并负责创建和管理 Pod 的副本。它支持滚动更新、回滚和扩缩容等操作。
  • Service:Service 定义了一组 Pod 的访问方式和网络策略,为 Pod 提供了稳定的网络端点。Service 可以通过负载均衡将请求分发到后端的 Pod上。
  • Namespace:Namespace 提供了一种逻辑隔离的机制,用于将集群中的资源划分为多个虚拟集群。不同的 Namespace 可以拥有独立的资源配额、访问控制策略等。
  • Volume:Volume 是用于持久化数据的抽象,它可以在 Pod 之间共享和持久化存储数据。k8s 支持多种类型的 Volume,如本地磁盘、网络存储等。

除了上述核心概念之外,k8s 还提供了许多其他功能,包括自动扩展、存储管理、配置管理、日志和监控等。它支持水平扩展和自动化恢复,可以根据应用程序的资源需求和约束条件自动调度和管理容器的运行。k8s 还提供了丰富的 API 和命令行工具,使得开发者和运维人员可以方便地管理和操作容器化应用。

k8s 的设计目标是高度可扩展和高可用的,可以在大规模的集群上运行和管理应用程序。它可以部署在各种云平台和裸机环境中,支持多种操作系统和容器运行时。k8s 已经成为容器编排领域的事实标准,被广泛应用于云原生应用的开发和运维中。

为什么要使用k8s?

自动化部署和扩展

Kubernetes 能够自动处理容器的部署、扩展和更新。当应用程序需要更多资源时,它可以自动增加容器实例的数量;当负载减少时,它也能自动缩减实例,从而优化资源使用。这种自动化大大减少了运维工作量,提高了系统的可靠性。

自愈能力

Kubernetes 具有强大的自愈能力。如果某个容器发生故障或者节点宕机,Kubernetes 可以自动检测并重新启动容器,或者将工作负载迁移到健康的节点上。这确保了应用程序的持续可用性。

负载均衡

通过 Service 机制,Kubernetes 提供了内置的负载均衡功能。它可以自动将流量分发到多个容器实例上,提高应用程序的性能和可用性。同时,它还支持多种服务发现机制,使得微服务架构更容易实现。

配置管理

Kubernetes 提供了 ConfigMap 和 Secret 等资源类型,用于管理应用程序的配置信息。这使得配置的更新和管理变得更加简单和安全,同时也支持配置的版本控制和回滚。

存储编排

通过持久化卷(Persistent Volume)和存储类(Storage Class),Kubernetes 提供了灵活的存储管理解决方案。它支持多种存储后端,并且能够自动处理存储的供应和回收。

声明式配置

Kubernetes 采用声明式配置方法,用户只需要描述期望的状态,Kubernetes 会自动确保系统达到并维持这个状态。这种方式使得系统配置更加可预测和可维护。

Yaml描述了我们期待的资源的形态,k8s会自动根据配置文件确定我们希望集群趋向的最终形态,并且自动维护.

可移植性

由于 Kubernetes 的标准化和广泛支持,使用 Kubernetes 部署的应用程序可以轻松地在不同的环境中运行,包括公有云、私有云和混合云环境。这种可移植性大大降低了供应商锁定的风险。

生态系统

Kubernetes 拥有庞大的生态系统,包括监控、日志收集、CI/CD、服务网格等多个领域的工具和解决方案。这些工具可以与 Kubernetes 无缝集成,提供完整的云原生应用开发和运维解决方案。

NameSpace

它是所有服务的统领旗帜.

概念

k8s中,命名空间(Namespace) 提供一种机制同一集群中的资源划分为相互隔离的组,同一命名空间内的资源名称要唯一,命名空间是用来隔离资源的,不隔离网路。

kubernetes启动时会创建四个初始命名空间:

default
kubernetes包含这个命名空间,以便你无需创建新的命名空间即可开始使用新集群

kube-node-lease
该命名空间包含用于各个节点关联的Lease(租约)对象。节点租约允许kubelet发送心跳,由此控制能够检测到节点故障。

kube-public
所有的客户端(包括未经身份验证的客户端)都可以读取该命名空间。该命名空间主要预留未集群使用,以便某些资源需要在整个集群中可见可读。该命名空间的公属性是一种约定而非要求.

kube-system
该命名空间使用kubernetes系统创建的对象.

使用

命令行方式

1
kubectl create namespace <namespace>

声明式部署

首先撰写一个yaml配置文件:

my-namespace.yaml

1
2
3
4
apiVersion: v1
kind: Namespace
metadata:
name: my-namespace

然后运行

1
kubectl apply -f my-namespace.yaml

Pod

Pod是实际运行的提供服务的部分.它定义了我们提供什么样的服务.

概念

Pod是Kubernetes中的最小调度单元,一个Pod封装一个容器(也可以封装多个容器),Pod里的容器共享存储、网络等。也就是说,可以把整个pod看作虚拟机,然后每个容器相当于运行在虚拟机的进程。同一个pod里的所有容器都被统一安排和调度。

Pod和Docker容器的区别是,Pod中可以包含多个Container,并且对于各个容器来说,使用127.0.0.1可以访问到各个container的服务.但文件系统完全隔离.一个pod中有一个pause容器和若干个业务容器,而容器是单独的一个容器,简而言之,pod是一组容器的集合。

使用

命令行方式

创建一个简单的pod

1
kubectl run mynginx --image=<image name>

找不到对应的image会自动去dockerhub/指定的镜像源拉取镜像.

一些常用的命令

1
2
3
4
5
6
kubectl get pod #获取pod的信息
kubectl get pod -owide # -owide 表示更详细的显示信息
kubectl get pod -n <namespace-name> # -n 命名空间 查询对应namespace下的pod
kubectl describe pod <pod-name> #查看pod的详情
kubectl logs <pod-name> #查看pod的运行日志
kubectl delete pod <pod-name> #删除pod

声明式部署

nginx-pod.yaml

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Pod
metadata:
labels:
run: mynginx
name: mynginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
1
kubectl apply -f nginx-pod.yaml

Deployment

Deployment是用来管理Pod状态的组件.它定义了我们的服务如何被部署运行.

概念

Deployment 是 Kubernetes 中最常用的资源类型之一,它用于管理无状态应用的部署和更新。其主要功能包括:

  1. Pod 管理
  • 确保指定数量的 Pod 副本在运行
  • 当 Pod 发生故障时自动重启
  • 支持水平扩缩容
  • 提供声明式更新

使用

命令行方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#my-tomcat表示pod的名称 --image表示镜像的地址 
kubectl create deployment <deployment-name> --image=<image-name>

#查看一下deployment的信息
kubectl get deployment

#删除deployment
kubectl delete deployment my-tomcat

#查看Pod打印的日志
kubectl logs my-tomcat-6d6b57c8c8-n5gm4

#使用 exec 可以在Pod的容器中执行命令
kubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- env #使用 env 命令查看环境变量
kubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- ls / # 查看容器的根目录下面内容
kubectl exec my-tomcat-6d6b57c8c8-n5gm4 -- sh #进入Pod容器内部并执行bash命令,如果想退出

声明式部署

tomcat-deployment.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
labels:
app: tomcat-deployment
spec:
replicas: 3 # 定义了 3 个副本
selector:
matchLabels:
app: tomcat-deployment
template:
metadata:
labels:
app: tomcat-deployment
spec:
containers:
- name: tomcat
image: tomcat:9.0.55
1
kubectl apply -f tomcat-deployment.yaml

动态扩缩容

手动

1
2
3
4
5
6
7
# 扩容到5个pod
kubectl scale --replicas=5 deployment my-tomcat
# 缩到3个pod
kubectl scale --replicas=3 deployment my-tomcat

#修改 replicas
kubectl edit deployment my-tomcat

HPA动态扩缩容

参考Pod 水平自动扩缩

HPA 可以根据一些指标(如 CPU 使用率、内存使用率或自定义指标)自动调整 Pod 的数量。

image-20250219172121897

hpa.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: tomcat-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-tomcat
minReplicas: 2 # 最小副本数
maxReplicas: 10 # 最大副本数
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80 # CPU 使用率超过 80% 触发扩容

应用hpa

1
2
3
4
kubectl apply -f hpa.yaml

# 查看 HPA 状态
kubectl get hpa

滚动升级和回滚

Service

Service是用来暴露服务的组件.它定义了我们的服务的访问策略.

概念

Service是一个抽象层,它定义了一组Pod的逻辑集,并为这些Pod支持外部流量暴露、负载均衡和服务发现。

尽管每个Pod都有一个唯一的IP地址,但是如果没有Service,这些IP不会暴露在集群外部。

Service允许你的应用程序接受流量.

Service也可以用在ServiceSpec标记type的方式暴露,type类型如下:

  • ClusterIP(默认):在集群的内部公开Service,这种类型使得Service只能从集群访问.
  • NodePort:使用NAT在集群中每个选定Node的相同端口上公开Service.使用<NodeIP>:<NodePort>从集群外部访问Service,是ClusterIP的超集.
  • LoadBalancer:在当前云中创建一个外部负载均衡器(如果支持的话),并为Service分配一个固定的外部IP,是NodePort的超集.
  • ExternalName:通过返回带有该名称的CNAME记录,使用任意名称(由spec中的externalName指定)公开Service,不使用代理.

使用

命令行方式

1
2
3
kubectl expose deployment my-tomcat --port=8080 --type=NodePort
kubectl get svc -owide #查看service信息,port信息冒号后面的端口号就是对集群外暴露的访问接口
#NodePort范围在 30000-32767之间

使用集群节点的ip加上暴露的端口就可以访问.

声明式部署

my-tomcat-svc.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
labels:
app: my-tomcat
name: my-tomcat # Service 的名称
spec:
ports:
- port: 8080 #service的虚拟ip对应的端口,在集群内网机器可以访问用service的虚拟ip加该端口号访问
nodePort: 30001 #Service在宿主主机上映射的外网访问端口,端口范围必须在30000~32767
protocol: TCP
port: 80 # Service 暴露的端口
targetPort: 8080 # 被暴露的 Pod 的容器端口,一般与pod内部容器暴露的端口一致
selector:
app: my-tomcat
type: NodePort # Service 类型,可以是 ClusterIP、NodePort、LoadBalancer 等
1
kubectl apply -f my-tomcat-svc.yaml

Volume

Volume是一个持久化层,它允许我们将数据持久化并分门别类储存,提高了数据的安全性.

概念

Volume指的是存储卷,包含可被Pod中容器访问的数据目录。容器中的文件在磁盘上是临时存放的,当容器崩溃时文件会丢失,同事无法在多个Pod中共享文件,通过使用存储卷可以解决这问题。

kubernetes 支持很多类型的卷。Pod可以同时使用任意数目的卷类型。临时卷类型的生命周期与Pod相同,但持久卷可以比Pod的存活期长。当Pod不再存在时,kubernetes 也会销毁临时卷;不过kubernetes 不会销毁永久卷。对于给定的Pod中任何类型的卷,在容器重启期间数据都不会丢失。

卷的核心就是一个目录,其中可能存有数据,Pod中的容器可以访问该目录中的数据。所采用的不同卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的东西。常见有configMap、emptyDir、local、nfs、secret等。

  • ConfigMap:可以将配置文件以键值对的形式保存到ConfigMap中,并且可以在Pod中以文件或环境变量的形式使用。ConfigMap可以用来存储不敏感的配置信息,如应用程序的配置文件。

  • EmptyDir:是一个空目录,可以在Pod用来存储临时数据,当Pod删除时,该目录也会删除。

  • Local:将本地文件系统的目录或文件映射到Pod中的一个Volume中,可以用来在Pod中共享文件或数据。

  • NFS:将网络上的一个或多个NFS共享目录挂载到Pod中的Volume中,可以用来在多个Pod之间共享数据。

  • Secret:将敏感信息以密文的形式保存到Secret中,并且可以在Pod中以文件或环境变量的形式使用。Secret可以用来存储敏感信息,如用户的密码、证书等。

常见的Volume类型

emptyDir

  • 临时存储,随 Pod 生命周期创建和删除
  • 适合同一个 Pod 中容器间的数据共享
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: container1
image: nginx
volumeMounts:
- name: shared-data
mountPath: /cache
volumes:
- name: shared-data
emptyDir: {}

hostPath

  • 挂载宿主机的目录或文件
  • 注意:使用 hostPath 可能带来安全风险
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
containers:
- name: web
image: nginx
volumeMounts:
- name: test-volume
mountPath: /test-data
volumes:
- name: test-volume
hostPath:
path: /data # 宿主机上的路径
type: Directory # 类型:Directory, File, Socket, etc.

PersistentVolume (PV) +PersistentVolumeClaim (PVC)

  • PV 是集群中的一块存储
  • PVC 是对 PV 的请求
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
# 创建 PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/pv-example

---
# 创建 PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi

---
# Pod 使用 PVC
apiVersion: v1
kind: Pod
metadata:
name: pod-with-pvc
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: pvc-example

ConfigMap 作为 Volume

  • 用于注入配置文件
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
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx.conf: |
server {
listen 80;
server_name localhost;
}

---
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: config-volume
configMap:
name: nginx-config

StorageClass

  • 动态供应 PV 的机制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2

---
# 使用 StorageClass 的 PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi

Volume 的访问模式

  • ReadWriteOnce (RWO): 只能被一个节点以读写方式挂载
  • ReadOnlyMany (ROX): 可以被多个节点以只读方式挂载
  • ReadWriteMany (RWX): 可以被多个节点以读写方式挂载
  1. 常见用例:数据库持久化

    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
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
    name: mysql
    spec:
    serviceName: mysql
    replicas: 1
    selector:
    matchLabels:
    app: mysql
    template:
    metadata:
    labels:
    app: mysql
    spec:
    containers:
    - name: mysql
    image: mysql:5.7
    volumeMounts:
    - name: mysql-data
    mountPath: /var/lib/mysql
    volumeClaimTemplates:
    - metadata:
    name: mysql-data
    spec:
    accessModes: [ "ReadWriteOnce" ]
    resources:
    requests:
    storage: 10Gi
  2. 最佳实践:

  • 优先使用 PVC/PV 机制而不是直接使用 hostPath
  • 为不同的应用场景选择合适的 StorageClass
  • 正确设置访问模式和容量
  • 考虑数据备份和恢复策略
  • 注意存储性能要求

FAQ

使用HPA实现动态扩缩容

1.基本概念

HPA 可以根据一些指标(如 CPU 使用率、内存使用率或自定义指标)自动调整 Pod 的数量。

2.创建 HPA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: tomcat-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-tomcat
minReplicas: 2 # 最小副本数
maxReplicas: 10 # 最大副本数
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80 # CPU 使用率超过 80% 触发扩容

3.应用配置

1
2
3
4
kubectl apply -f hpa.yaml

# 查看 HPA 状态
kubectl get hpa

4.多指标配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spec:
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: packets-per-second
target:
type: AverageValue
averageValue: 1k

5.自定义指标

你还可以根据自定义指标进行扩缩容,比如:

  • 请求队列长度
  • 每秒请求数(QPS)
  • 响应时间
  • 并发连接数
1
2
3
4
5
6
7
8
9
10
11
12
spec:
metrics:
- type: External
external:
metric:
name: queue_messages
selector:
matchLabels:
queue: "worker_tasks"
target:
type: AverageValue
averageValue: 30

6.配置扩缩容行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spec:
behavior:
scaleUp:
stabilizationWindowSeconds: 0 # 立即扩容
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleDown:
stabilizationWindowSeconds: 300 # 等待 5 分钟再缩容
policies:
- type: Percent
value: 100
periodSeconds: 15

要让 HPA 正常工作,需要确保:

  1. 集群已安装 metrics-server
  2. 设置了合适的资源请求(requests)和限制(limits)
  3. 应用程序支持水平扩展

检查 metrics-server:

1
2
3
4
5
# 安装 metrics-server(如果未安装)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 验证安装
kubectl get apiservice v1beta1.metrics.k8s.io

这样,应用就能根据负载自动调整副本数,在高峰期自动扩容,在低谷期自动缩容,既保证了服务质量,又节省了资源。

服务绑定指定域名

要将服务绑定到指定域名,我们需要设置 Ingress 资源。Ingress 可以管理集群外部访问集群内服务的规则,通常用于配置 HTTP/HTTPS 路由。

1.首先确保集群安装了 Ingress Controller(如 Nginx Ingress Controller):

1
2
3
4
5
# 安装 Nginx Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml

# 验证安装
kubectl get pods -n ingress-nginx

2.创建 Ingress 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # 重写路径
spec:
rules:
- host: k8s.ec3o.fun # 指定域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-tomcat # 服务名称
port:
number: 80 # 服务端口

3.应用配置

1
2
3
4
kubectl apply -f ingress.yaml

# 查看 Ingress 状态
kubectl get ingress

4.如果需要配置 HTTPS,需要先创建 TLS 证书的 Secret:

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
# 创建 TLS Secret
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: <base64 编码的证书>
tls.key: <base64 编码的私钥>
---
# 在 Ingress 中启用 HTTPS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
tls:
- hosts:
- k8s.ec3o.fun
secretName: tls-secret
rules:
- host: k8s.ec3o.fun
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-tomcat
port:
number: 80

5.最后,需要配置 DNS:

  • 获取 Ingress Controller 的外部 IP 或负载均衡器地址:
1
kubectl get service -n ingress-nginx
  • 在你的 DNS 提供商处添加 A 记录,将 k8s.ec3o.fun 指向该 IP 地址

完成这些配置后,通过域名就可以访问你的服务了。要注意:

  • 确保域名已经解析到正确的 IP
  • 如果使用 HTTPS,确保证书正确配置
  • 检查 Ingress Controller 的日志以排查可能的问题
  • 可能需要等待 DNS 解析生效(通常几分钟到几小时不等)