运维面经

2025/01/13 腾讯音乐运维一面

Linux

Linux启动顺序

BIOS/UEFI阶段

BIOS(Basic Input Output System):基本输入输出系统。它是一组固化到计算机内主板上一个daoROM芯片上的程序,它保存着计算机最重要的基本输入输出的程序、系统设置信息、开机后自检程序和系统自启动程序。 其主要功能是为计算机提供最底层的、最直接的硬件设置和控制。BIOS应该是连接软件程序与硬件设备的一座"桥梁",负责解决硬件的即时要求。简单地说,BIOS就是一个加载在计算机主板上最基础的一段程序,负责最基础的硬件控制和设置。

MBR(Master Boot Record):主引导程序,是分区计算器大容量存储设备(如固定硬盘或移动硬盘)的第一个块中的一种引导扇区。

加载位于主板ROM中地址0xFFFF0的BIOS信息,主要包括系统BIOS和显卡BIOS;进行POST自检,检查CPU、内存、主板等硬件;建立终端向量表和中断服务程序;检测可引导设备;加载MBR(主引导程序)的前446字节到内存0x7c00处。

注:老电脑用MBR,较新的电脑,2017年之后的系统如Ubuntu17.04都默认使用GPT+UEFI组合。UEFI最大的好处就是启动方便,有图形化界面。

目前主板多设置成三种启动模式,即:Auto、UEFI、Legacy。在设置启动时,带有UEFI的BIOS还提供了启动选项供大家选择以何种方式启,各种模式含义如下:

Auto(自动)/Both:自动按照启动设备列表中的顺序启动,优先采用UEFI方式;

UEFI only(仅UEFI):只选择具备UEFI启动条件的设备启动;

Legacy only(仅Legacy):只选择具备Legacy启动条件的设备启动。

简单的来说uefi启动是新一代的bios,功能更加强大,而且它是以图形图像模式显示,让用户更便捷的直观操作。

MBR最大支持2TB硬盘;最多支持4个主分区,或3个主分区+1个扩展分区;扩展分区可以包含多个逻辑分区;分区表只有一份,易损坏;启动代码占446字节,分区表占64字节;兼容传统BIOS系统 GPT (GUID Partition Table)支持超过2TB的硬盘(最大18EB);支持最多128个分区(理论上可更多);分区表有主副两份,更安全;每个分区都有全球唯一标识符(GUID);支持更多分区类型;需要UEFI启动支持

Boot Loader阶段

显示内核选择菜单;加载选定的内核镜像到内存;加载initramfs到内存;然后将控制权移交给内核

Kernel初始化阶段

系统读取内存映像,并进行解压缩操作。此时,屏幕一般会输出“Uncompressing Linux”的提示。当解压缩内核完成后,屏幕输出“OK, booting the kernel”。 系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。 然后系统会初始化CPU、内存、设备驱动;挂载根文件系统;运行/sbin/init(PID 1)

Init进程(systemd)阶段

Unit:systemd管理的基本单元,包括service服务socket进程间通信套接字target启动目标(类似于运行级别)mount文件系统挂载点device设备文件timer定时器。配置文件优先级依次是:/etc/systemd/system/ 系统管理员创建的配置,优先级最高;/run/systemd/system/ 运行时配置文件;/usr/lib/systemd/system/软件包安装的默认配置。

读取默认target配置文件;分析unit间依赖关系;激活系统服务;准备各类daemon进程;准备用户环境。

备注:系统级自启动程序就是在这时候启动的,如通过apt安装的Mysql、Docker。

用户空间阶段

依次读取/etc/profile系统环境变量、 ~/.bashrc用户环境变量、 /etc/passwd用户账户信息、 /etc/shadow用户密码信息 启动显示管理器,加载桌面环境,准备终端设备;等待用户登录

备注:用户级自启动程序在读取~/.bashrc后自动执行,也就是说想要设置用户级自启动命令可以将启动命令写入到~/.bashrc

Linux开机自启动

Linux有三种级别的开机自启动:

系统级别

通过apt包管理器安装的包默认就是这种级别的开机自启。 可以通过 sudo systemctl enable mysql来启用开机自启(sudo systemctl disable mysql为关闭开机自启命令)。

除了包管理器,还可以自己制作service来实现,以nginx为例:

  1. /etc/systemd/system/下创建nginx.service文件
1
2
cd /etc/systemd/system/
vim nginx.service

写入如下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Unit]
Description=nginx - high performance web server
After=nginx.service
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
Execenable=/usr/local/nginx/sbin/nginx
[Install]
WantedBy=multi-user.target
  1. 设置开机自启
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 设置开机启动
systemctl enable nginx
# 取消开机自启动
#systemctl disable nginx
# 查看服务当前状态
systemctl status nginx
# 启动nginx服务
systemctl start nginx
# 停止nginx服务
systemctl stop nginx
# 重启nginx服务
systemctl restart nginx

用户级别

将需要自启动的命令写入~/.bashrc中,即可实现用户级开机自启。具体操作时如果命令较为简单,比如使用alias给命令指定别名或者ulimit -n 65536修改最大打开文件句柄数(我的Ubuntu不知道为什么永久修改怎么也修改不成功,只能通过这种方式曲线救国),就可以直接把命令写到~/.bashrc中。如果命令比较复杂,可以考虑将命令打包成脚本,然后在~/.bashrc中执行启动脚本的命令。

桌面级别

大体步骤类似系统级自启动:切换到/etc/xdg/autostart/目录,创建后缀为desktop的文件,编辑并保存。重启生效。

数据库

MySQL主从复制配置过程,宕机恢复

参考资料:https://xiaolincoding.com/mysql/log/how_update.html#%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E6%98%AF%E6%80%8E%E4%B9%88%E5%AE%9E%E7%8E%B0

主从复制可以用来做数据库的实时备份,保证数据的完整性;也可以做读写分离,提升数据库系统整体的读写性能。

主从复制原理:

MySQL集群的主从复制过程梳理成3个阶段:

  • 写入 Binlog:主库写 binlog 日志,提交事务,并更新本地存储数据。
  • 同步 Binlog:把 binlog 复制到所有从库上,每个从库把 binlog 写到暂存日志中。
  • 回放 Binlog:回放 binlog,并更新存储引l擎中的数据。 具体详细过程如下:
  1. MySQL 主库在收到客户端提交事务的请求之后,会先写入binlog,再提交事务,更新存储引擎中的数 据,事务提交完成后,返回给客户端"操作成功"的响应。
  2. 从库会创建一个专门的 I/O 线程,连接主库的 log dump 线程,来接收主库的 binlog 日志,再把 binlog 信息写入 relay log 的中继日志里,再返回给主库"复制成功"的响应。
  3. 从库会创建一个用于回放 binlog 的线程,去读 relay log 中继日志,然后回放 binlog 更新存储引擎中 的数据,最终实现主从的数据一致性。 在完成主从复制之后,你就可以在写数据时只写主库,在读数据时只读从库,这样即使写请求会锁表或者 锁记录,也不会影响读请求的执行。

主从复制配置过程

参考资料:https://www.cnblogs.com/nulige/articles/9273537.html 两台机器都操作,确保 server-id 要不同,通常主ID要小于从ID。一定注意。

MySQL binlog格式

binlog 是 MySQL 中的一种重要日志类型,用于记录所有的DDL和DML操作(不包括数据查询语句)。它主要用于数据恢复和主从复制。Binlog有三种模式:STATEMENT(语句模式)、ROW(行模式) 和 MIXED(混合模式)

STATEMENT模式:基于SQL语句的复制(Statement-Based Replication, SBR),每一条修改数据的SQL语句都会记录到binlog中

  • 优点:减少日志量:不需要记录每一行数据的变化,减少了磁盘IO,提高了性能
  • 缺点:数据不一致:在某些情况下,主从库的数据可能会不一致。例如,使用 uuid() 函数时,每次执行都会生成不同的值;自增字段在执行时可能得到错误的值

ROW模式:基于行的复制(Row-Based Replication, RBR),不记录SQL语句的上下文信息,仅记录哪条数据被修改了

  • 优点:准确复制:不会出现存储过程、函数或触发器调用无法正确复制的问题
  • 缺点:日志量大:尤其是在执行批量更新或删除操作时,会产生大量日志,影响IO性能

MIXED模式:是前两种模式的混合体(Mixed-Based Replication, MBR),MySQL会根据具体的SQL语句选择使用STATEMENT或ROW模式。 一般情况下,使用STATEMENT模式保存binlog,对于无法准确复制的操作则使用ROW模式

配置和查看Binlog

要开启和配置Binlog,可以修改MySQL的配置文件 my.cnf

1
2
3
4
[mysqld]
log-bin=ON
binlog_format=mixed
server-id=1

查看Binlog日志可以使用 mysqlbinlog 工具

1
mysqlbinlog mysql-bin.000001

或者使用SQL命令查看事件:

1
SHOW BINLOG EVENTS IN 'mysql-bin.000001';

通过合理选择和配置Binlog模式,可以有效提高MySQL的性能和数据一致性

MySQL 备份,逻辑备份与物理备份

MySQL的物理备份和逻辑备份的主要区别在于备份文件的形式和备份恢复的灵活性。 物理备份直接复制数据库的二进制文件(binlog),备份文件较大,恢复时只能在相同架构的MySQL服务器上使用。 逻辑备份将数据库导出为SQL语句的形式,备份文件较小,恢复时可跨平台使用,也可以进行数据的修改和筛选。

容器化

k8s移动pod

参考资料:https://blog.csdn.net/yanggd1987/article/details/108139436

k8s集群中的node节点要升级内存,以应对服务迁入、pod扩缩容导致的资源短缺,需要对node节点进行停机维护。此时就需要对pod进行迁移。

默认迁移

当node节点关机后,k8s集群并没有立刻发生任何自动迁移动作,如果该node节点上的副本数为1,则会出现服务中断的情况。其实事实并非如此,k8s在等待5分钟后,会自动将停机node节点上的pod自动迁移到其他node节点上。

 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
# 1.模拟node节点停机,停止kubelet
systemctl stop kubelet

# 2.集群状态
# 此时停机的node点处于NotReady状态
# kubectl get node
NAME                STATUS     ROLES     AGE   VERSION
k8s-3-217   Ready        master     88d   v1.18.2
k8s-3-218   NotReady   <none>   88d   v1.18.2
k8s-3-219   Ready        <none>   88d   v1.18.2

# 3.监控pod状态,大约等待5分钟左右,集群开始有动作
# kubectl get pod -n test -o wide -n test -w
NAME                                   READY   STATUS    RESTARTS   AGE   IP             NODE           NOMINATED NODE   READINESS GATES
helloworld-79956d95b4-q7jjg            1/1     Running   0          19h   10.244.1.154   k8s-3-218   <none>           <none>
helloworld-79956d95b4-q7jjg            1/1     Running   0          19h   10.244.1.154   k8s-3-218   <none>           <none>
# 5分钟后,pod终止并进行重建
helloworld-79956d95b4-q7jjg            1/1     Terminating   0          19h   10.244.1.154   k8s-3-218   <none>           <none>
helloworld-79956d95b4-nnlrq            0/1     Pending       0          0s    <none>         <none>         <none>           <none>
helloworld-79956d95b4-nnlrq            0/1     Pending       0          0s    <none>         k8s-3-219   <none>           <none>
helloworld-79956d95b4-nnlrq            0/1     ContainerCreating   0          1s    <none>         k8s-3-219   <none>           <none>

helloworld-79956d95b4-nnlrq            0/1     Running             0          3s    10.244.2.215   k8s-3-219   <none>           <none>
helloworld-79956d95b4-nnlrq            1/1     Running             0          66s   10.244.2.215   k8s-3-219   <none>           <none>

# 4.访问测试:在pod重新迁移到其他node节点时,服务是不可用的。
# curl -x 192.168.3.219:80 hello.test.cn
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.17.8</center>

# 5.迁移完毕:服务正常访问
# curl -x 192.168.3.219:80 hello.test.cn
Hello,world!

从以上过程看出,停机node节点上的pod在5分钟后先终止再重建,直到pod在新节点启动并由readiness探针检测正常后并处于1\1 Running状态才可以正式对外提供服务。因此服务中断时间=停机等待5分钟时间+重建时间+服务启动时间+readiness探针检测正常时间。

为什么pod在5分钟后开始迁移呢? 此时需要涉及到k8s中的Taint(污点)和 Toleration(容忍),这是从Kubernetes 1.6开始提供的高级调度功能。Taint和Toleration相互配合,可以避免pod被分配到不合适的节点上。每个节点上都可以应用一个或多个Taint,这表示对于那些不能容忍Taint的pod,是不会被该节点接受的。如果将Toleration应用于pod上,则表示这些pod可以(但不要求)被调度到具有匹配Taint的节点上。

 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
# 1.查看停止服务节点的状态
# kubelet停止后,node节点自动添加了Taints;
# kubectl describe node k8s-3-218

Name:               k8s-3-218
Roles:              <none>
CreationTimestamp:  Fri, 22 May 2020 11:36:16 +0800
Taints:             node.kubernetes.io/unreachable:NoExecute
                    node.kubernetes.io/unreachable:NoSchedule
Unschedulable:      false
Lease:
  HolderIdentity:  k8s-3-218
  AcquireTime:     <unset>
  RenewTime:       Wed, 19 Aug 2020 09:31:22 +0800
Conditions:
  Type                 Status    LastHeartbeatTime                 LastTransitionTime                Reason              Message
  ----                 ------    -----------------                 ------------------                ------              -------
  NetworkUnavailable   False     Tue, 18 Aug 2020 09:07:59 +0800   Tue, 18 Aug 2020 09:07:59 +0800   FlannelIsUp         Flannel is running on this node
  MemoryPressure       Unknown   Wed, 19 Aug 2020 09:29:56 +0800   Wed, 19 Aug 2020 09:32:07 +0800   NodeStatusUnknown   Kubelet stopped posting node status.
  DiskPressure         Unknown   Wed, 19 Aug 2020 09:29:56 +0800   Wed, 19 Aug 2020 09:32:07 +0800   NodeStatusUnknown   Kubelet stopped posting node status.
  PIDPressure          Unknown   Wed, 19 Aug 2020 09:29:56 +0800   Wed, 19 Aug 2020 09:32:07 +0800   NodeStatusUnknown   Kubelet stopped posting node status.
  Ready                Unknown   Wed, 19 Aug 2020 09:29:56 +0800   Wed, 19 Aug 2020 09:32:07 +0800   NodeStatusUnknown   Kubelet stopped posting node status.
...省略...
Events:              <none>

# 2.查看pod状态
# kubectl describe pod helloworld-8565c4687b-rrfmj -n test
Name:                      helloworld-8565c4687b-rrfmj
Namespace:                 test
Priority:                  0
......
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:          <none>

此时pod的Tolerations 默认对于具有相应Taint的node节点容忍时间为300s,超过此时间pod将会被驱逐到其他可用node节点上。因此5分钟后node节点上所有的pod重新被调度,在此期间服务是中断的。

手动迁移

默认的pod迁移无法避免服务中断,那么我们在node节点停机前,我们可以手动迁移。 为避免等待默认的5分钟,我们还可以使用cordon、drain、uncordor三个命令实现节点的主动维护。此时需要用到以下三个命令:

  • cordon:标记节点不可调度,后续新的pod不会被调度到此节点,但是该节点上的pod可以正常对外服务;
  • drain:驱逐节点上的pod至其他可调度节点;
  • uncordon:标记节点可调度 具体操作如下:
 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
# 1.标记节点不可调度
# kubectl cordon k8s-3-219
node/k8s-3-219 cordoned

# 查看节点状态,此时219被标记为不可调度
# kubectl get node
NAME           STATUS                     ROLES    AGE   VERSION
k8s-3-217   Ready                      master   89d   v1.18.2
k8s-3-218   Ready                      <none>   88d   v1.18.2
k8s-3-219   Ready,SchedulingDisabled   <none>   88d   v1.18.2

# 2.驱逐pod
# kubectl drain k8s-3-219 --delete-local-data --ignore-daemonsets --force
node/k8s-3-219 already cordoned
WARNING: ignoring DaemonSet-managed Pods: ingress-nginx/nginx-ingress-controller-gmzq6, kube-system/kube-flannel-ds-amd64-5gfwh, kube-system/kube-proxy-vdckk
evicting pod kube-system/tiller-deploy-6c65968d87-75pfm
evicting pod kube-system/metrics-server-7f96bbcc66-bgt7j
evicting pod test/helloworld-79956d95b4-nnlrq

# 参数如下:
--delete-local-data  删除本地数据,即使emptyDir也将删除;
--ignore-daemonsets  忽略DeamonSet,否则DeamonSet被删除后,仍会自动重建;
--force  不加force参数只会删除该node节点上的ReplicationController, ReplicaSet, DaemonSet,StatefulSet or Job,加上后所有pod都将删除;

# 3. 查看驱逐,219上的pod迁移到218上了。
# kubectl get pod -n test -o wide
NAME                                   READY   STATUS        RESTARTS   AGE   IP             NODE           NOMINATED NODE   READINESS GATES
helloworld-79956d95b4-gg58c            0/1     Running       0          20s   10.244.1.165   k8s-3-218   <none>           <none>
helloworld-79956d95b4-nnlrq            1/1     Terminating   0          77m   10.244.2.215   k8s-3-219   <none>           <none>

此时与默认迁移不同的是,pod会先重建再终止,此时的服务中断时间=重建时间+服务启动时间+readiness探针检测正常时间,必须等到1/1 Running服务才会正常。因此在单副本时迁移时,服务中断是不可避免的。

平滑迁移

要做到平滑迁移就需要用的pdb(PodDisruptionBudget),即主动驱逐保护。无论是默认迁移和手动迁移,都会导致服务中断,而pdb能可以实现节点维护期间不低于一定数量的pod正常运行,从而保证服务的可用性。

在仍以helloworld为例,由于只有一个副本,因此需要保证维护期间这个副本在迁移完成后,才会终止。

 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
# 从218 驱逐到 219
# 1.标记节点不可调度
# kubectl cordon k8s-3-218
node/k8s-3-218 cordoned

# 2.新建pdb
vim pdb-test.yaml
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: pdb-test
  namespace: test
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: helloworld

# 2.应用并查看状态
# kubectl apply -f pdb-test.yaml
# kubectl get pdb -n test
NAME       MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
pdb-test   1                         N/A                          0                                       7s

# 3.驱逐
# kubectl drain k8s-3-218 --delete-local-data --ignore-daemonsets --force
node/k8s-3-218 already cordoned
WARNING: ignoring DaemonSet-managed Pods: ingress-nginx/nginx-ingress-controller-hhb6h, kube-system/kube-flannel-ds-amd64-pb4d7, kube-system/kube-proxy-rzdcj
evicting pod kube-system/tiller-deploy-6c65968d87-ktqmm
evicting pod kube-system/metrics-server-7f96bbcc66-6p6wm
evicting pod test/helloworld-79956d95b4-gg58c
error when evicting pod "helloworld-79956d95b4-gg58c" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
evicting pod test/helloworld-79956d95b4-gg58c
error when evicting pod "helloworld-79956d95b4-gg58c" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
pod/tiller-deploy-6c65968d87-ktqmm evicted

#此时由于只有一个副本,最小可用为1,则ALLOWED就为0,因此在一个副本通过pdb是不会发生驱逐的。我们需要先扩容,将副本数调整为大于1。

# 3.手动调整副本数,将replicas为2
kubectl edit deploy helloworld -n test
# 再次查看pdb
# kubectl get pdb -n test
NAME       MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
pdb-test   1               N/A               1                     13m

#此时最小可用为1 ,ALLOWED为1,此时是数量会自动计算。

# 4.驱逐
# kubectl drain k8s-3-218 --delete-local-data --ignore-daemonsets --force

# 5.维护完毕,将node调整为可调度
# kubectl uncordon k8s-3-218

本次驱逐,由于helloworld始终保持有一个pod在提供服务,因此服务是不中断的。 最后将副本数可以调节为1并将node节点调整为可调度,维护完毕。

总结:通过简单了解了Taint(污点)和 Toleration(容忍)作用,我们既可以通过设置tolerationSeconds来缩短等待时间,也可以自行定义匹配规则实现符合实际情况的调度规则。

另外还要注意先重建再终止和先终止再重建,在此过程中服务启动时间和探针检测时间决定你的服务中断时间。

k8s镜像拉取配置参数及优先级

参考:https://www.cnblogs.com/leojazz/p/18686403

在 Kubernetes(简称 K8s)中,容器镜像的更新行为主要由 imagePullPolicy 参数控制。该策略决定了 Kubernetes 在启动或重启容器时是否从镜像仓库拉取新的镜像版本。常见的镜像更新策略有三种:

  1. Always 如果容器的imagePullPolicy设置为 Always,每次创建 Pod 或者重启容器时,Kubelet 都会从镜像仓库拉取最新的镜像版本。这对于使用 latest 标签或者希望始终获取最新镜像的场景非常有用,但在生产环境中应谨慎使用,因为 latest 标签的镜像内容可能会随时变化,导致版本不一致或潜在的不稳定。

建议: 在生产环境中避免直接使用 latest 标签,使用明确的版本号(如 v1.0.1)来确保一致性,并记录镜像版本历史以便于追踪和排查问题。

  1. IfNotPresent(默认值) 当imagePullPolicy设置为 IfNotPresent 时,如果本地节点上已经存在该镜像,则 Kubelet 不会尝试从镜像仓库拉取镜像;仅当本地不存在该镜像时,Kubelet 才会去远程仓库拉取镜像。通常,使用带有明确版本标签(如 v1.0)的镜像时,推荐使用此策略,以避免不必要的镜像拉取。

注意: 默认情况下,如果镜像标签是 latest,imagePullPolicy 会自动设置为 Always;如果是版本号标签(如 v1.0),则默认使用 IfNotPresent。

  1. Never 如果imagePullPolicy设置为 Never,无论本地是否存在该镜像,Kubelet 都不会尝试从镜像仓库拉取镜像,而是始终使用本地已有的镜像。这种策略适用于不希望自动升级镜像版本,且希望始终使用特定版本的场景。

更新应用镜像的常见方法 在 Kubernetes 中,更新应用镜像的常见方法是通过修改 Deployment、StatefulSet 等控制器中定义的 Pod 模板内的镜像版本,然后执行 kubectl apply 命令将更改推送到集群,触发滚动更新。

滚动更新的过程中,Kubernetes 会逐步替换旧的容器实例,确保服务的持续可用性。您可以使用以下命令来更新镜像版本:

示例:更新 Deployment 中的镜像 假设我们有一个名为 example-deployment 的 Deployment,其中定义了一个容器镜像 myapp:v1.0。我们将镜像版本更新为 myapp:v2.0,并通过 kubectl apply 命令触发更新。

修改 Deployment 配置文件 deployment.yaml 中的镜像版本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: example
  template:
    metadata:
      labels:
        app: example
    spec:
      containers:
      - name: example-container
        image: myapp:v2.0  # 修改为新的镜像版本
        imagePullPolicy: IfNotPresent

执行 kubectl apply 命令将变更推送到集群: kubectl apply -f deployment.yaml 在执行该命令后,Kubernetes 会根据定义的镜像更新策略(例如,imagePullPolicy: IfNotPresent)决定是否从仓库拉取新的镜像,并按滚动更新的方式逐步替换旧版本的容器实例。

滚动更新控制 在滚动更新过程中,您还可以通过以下参数控制更新过程的行为:

  • maxUnavailable:定义更新过程中允许不可用的最大 Pod 数量,控制更新期间服务的最小可用性。
  • maxSurge:定义在更新过程中可以超出期望副本数的最大 Pod 数量,帮助提升更新的速度。 合理设置这两个参数可以在保证服务可用性的同时加速或控制更新过程。例如:
1
2
3
4
5
6
spec:
  replicas: 3
  strategy:
    rollingUpdate:
      maxUnavailable: 1  # 最多允许 1 个 Pod 不可用
      maxSurge: 1        # 可以增加 1 个 Pod 以加速更新

通过设置这些参数,您可以精细控制容器的滚动更新行为,以平衡服务可用性和更新速度。

这种修订版本提供了更为清晰的策略解释、更新的实践方法和对滚动更新的详细控制,适用于生产环境中的实际操作。

k8s镜像仓库

k8s镜像仓库分为远程仓库和本地仓库。本地仓库就是存储在本机的镜像文件,可以通过工具(如Docker Registry、Harbor)搭建,用于管理和分发镜像;

由于 Kubernetes 使用的是容器运行时(如 containerd),直接在 Docker 中构建的镜像无法直接被 Kubernetes 使用。需要将镜像导入到对应的容器运行时中。

1
2
3
4
5
# containerd:使用 ctr 工具导入镜像
ctr -n k8s.io images import my-image.tar

# CRI-O:使用 skopeo 或 crictl 工具导入镜像
crictl load my-image.tar
  1. Kubernetes 较新版本(1.24+)已移除对 Docker 的支持,转为使用 containerd 或 CRI-O。
  2. 不同运行时的镜像存储路径如下:
  • Docker:/var/lib/docker
  • containerd:/var/lib/containerd
  • CRI-O:/var/lib/containers
  1. 如果需要使用本地镜像,需根据运行时类型将镜像导入到对应的存储系统中,例如使用 ctr 或 crictl。 Kubernetes 配置文件中需设置 imagePullPolicy 为 Never,并确保所有节点都加载了本地镜像。

远程仓库

  1. 公共镜像仓库: 这些仓库通常是开放和免费的,供开发者和用户共享或下载镜像。

    Docker Hub:Docker 官方提供的公共镜像仓库,默认与 Docker CLI 配合使用。

    Google Container Registry (GCR):Google 提供的镜像仓库(k8s1.24版本前的默认仓库),适合与 Google Cloud Platform (GCP) 集成。k8s1.24后的默认仓库:https://registry.k8s.io

    GitHub Container Registry (GHCR):GitHub 提供的容器镜像服务,适合与 GitHub 项目结合使用。

    Quay.io:Red Hat 提供的镜像仓库,支持高级功能和企业用途。

  2. 私有镜像仓库: 为了安全性和隐私原因,很多企业会搭建自己的私有镜像仓库。

    Harbor:一个开源的企业级私有镜像仓库,支持镜像管理、访问控制和漏洞扫描。

    Artifactory:JFrog 提供的企业级解决方案,支持多种包管理器,包括 Docker 镜像。

    自建私有仓库:使用 Docker Registry 开源项目搭建的简单私有仓库。

  3. 云厂商提供的镜像仓库: 各大云厂商为其云服务提供了专属的容器镜像仓库,方便与云平台集成。

    Amazon Elastic Container Registry (ECR):AWS 提供的镜像仓库,深度集成 AWS 生态。

    Azure Container Registry (ACR):Azure 提供的镜像仓库,支持与 Azure Kubernetes 服务无缝集成。

    Alibaba Cloud Container Registry (ACR):阿里云提供的镜像服务,支持国内加速访问和与阿里云服务集 成。

    Tencent Container Registry (TCR):腾讯云提供的镜像仓库,适合国内用户使用。

    Huawei Cloud SWR (SoftWare Repository for Container):华为云提供的容器镜像服务,支持企业级容器管理。

  4. 国内公共镜像加速器 由于国内网络环境的限制,许多镜像从国外仓库拉取较慢,因此国内厂商提供了一些公共镜像加速器。

    阿里云容器镜像服务加速器:https://cr.console.aliyun.com

    腾讯云容器镜像服务加速器:https://cloud.tencent.com/document/product/457/35996

    华为云容器镜像加速器:https://www.huaweicloud.com/product/swr.html

    网易云加速器:https://www.163yun.com/product/container

监控

参考:https://flashcat.cloud/blog/ops-monitor/

nginx

页面浏览量Loading
网站总访客数:Loading
网站总访问量:Loading
使用 Hugo 构建
主题 StackJimmy 设计