【问题小解决】无需重启,基于Prometheus对Pod进行垂直扩缩容

通常情况下,要修改 Pod 的资源定义,是需要重启 Pod 的。 在Kubernetes 1.27中,有一个 Alpha 状态的InPlacePodVerticalScaling开关,开启这一特性, 就能在不重启 Pod 的情况下,修改 Pod 的资源定义。

要使用这个功能,需要在kube-apiserverfeatureGates中显式地设置启用,启用这一特性之后,就可以进行测试了。

测试一下

假设下面的 Pod 定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: myimages/stress-ng:latest
    resizePolicy:
    - resourceName: cpu
      restartPolicy: NotRequired
    - resourceName: memory
      restartPolicy: RestartContainer    
    command: ["sleep", "3600"]
    resources:
      limits:
        cpu: 200m
        memory: 200M
      requests:
        cpu: 200m
        memory: 200M

可以看到,spec 中加入了resizePolicy字段,用来指定对 CPU 和内存的扩缩容策略。内容很直白:

  • CPU 的扩缩容策略是NotRequired,即不重启 Pod;
  • 内存的扩缩容策略是RestartContainer,即重启 Pod。
Read more...

【问题小解决】如何解决多容器下修改hosts失效

问题现象

业务容器启动的逻辑中,修改了/etc/hosts文件,当 Pod 只存在这一个业务容器时,文件可以修改成功, 但存在多个时 (比如注入了 istio 的 sidecar),修改可能会失效。

分析

  1. 容器中的/etc/hosts是由 kubelet 生成并挂载到 Pod 中所有容器, 如果 Pod 有多个容器,它们挂载的/etc/hosts文件都对应宿主机上同一个文件, 路径通常为/var/lib/kubelet/pods/<pod-uid>/etc-hosts

如果是 docker 运行时,可以通过docker inspect <container-id> -f {{.HostsPath}}查看。

  1. kubelet 在启动容器时,都会走如下的调用链(makeMounts->makeHostsMount->ensureHostsFile)来给容器挂载 /etc/hosts, 而在 ensureHostsFile 函数中都会重新创建一个新的 etc-hosts 文件,导致在其他容器中对 /etc/hosts 文件做的任何修改都被还原了。

所以,当 Pod 中存在多个容器时,容器内修改 /etc/hosts 的操作可能会被覆盖回去。

解决方案

使用 HostAliases

如果只是某一个 workload 需要 hosts,可以用 HostAliases:

Read more...

【问题小解决】解决容器内时区不一致问题

业务程序在使用时间的时候(比如打印日志),没有指定时区,使用的系统默认时区, 而基础镜像一般默认使用 UTC 时间,程序输出时间戳的时候,就与国内的时间相差 8 小时。

游戏全球对战服场景这个问题更要命,开发需要通过时间计算同步帧的偏移量,如果这个时候还要重新计算时区是非常浪费计算资源的(-_-)

方案一:指定 TZ 环境变量

很多编程语言都支持TZ这个用于设置时区的环境变量,可以在部署工作负载的时候,为容器指定该环境变量,示例:

Read more...

【问题小解决】提供一个直接进入Pod网络命名空间的Shell脚本

我们使用 Kubernetes 时难免发生一些网络问题,往往需要进入容器的网络命名空间 (netns) 中,进行一些网络调试来定位问题,这里直接提供一个脚本,申请各种步骤 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 #!/bin/bash # 函数:进入网络命名空间并进行调试 enter_netns() { local pod_name=$1 local namespace=$2 local container_name=$3 # 获取指定 Pod 中指定容器的容器 ID container_id=$(kubectl -n $namespace get pod $pod_name -o jsonpath="{.status.containerStatuses[?(@.name==\"$container_name\")].containerID}" | sed 's|containerd://||') if [ -z "$container_id" ]; then echo "未找到 Pod $pod_name 中容器 $container_name 在命名空间 $namespace 中的容器 ID" exit 1 fi # 获取容器进程的 PID pid=$(crictl inspect $container_id | grep -i '"pid"' | head -n 1 | awk '{print $2}' | sed 's/,//') if [ -z "$pid" ]; then echo "未找到容器 $container_id 的 PID" exit 1 fi # 进入容器的网络命名空间 echo "进入 Pod $pod_name 中容器 $container_name 的网络命名空间,PID 为 $pid" nsenter -n --target $pid } # 检查是否提供了必要的参数 if [ $# -ne 3 ]; then echo "用法: $0 <pod_name> <namespace> <container_name>" exit 1 fi # 调用函数进入网络命名空间 enter_netns $1 $2 $3 调试网络 成功进入容器的 netns,可以使用节点上的网络工具进行调试网络,可以首先使用ip a验证下 ip 地址是否为 pod ip:
Read more...

【问题小解决】PID耗尽的危害

如何判断 PID 耗尽

首先要确认当前的 PID 限制,检查全局 PID 最大限制:

1
cat /proc/sys/kernel/pid_max

也检查下线程数限制:

1
cat /proc/sys/kernel/threads-max

再检查下当前用户是否还有ulimit限制最大进程数。

确认当前实际 PID 数量,检查当前用户的 PID 数量:

1
ps -eLf | wc -l

如果发现实际 PID 数量接近最大限制说明 PID 就可能会爆满导致经常有进程无法启动, 低版本内核可能报错:Cannot allocate memory,这个报错信息不准确, 在内核 4.1 以后改进了: https://github.com/torvalds/linux/commit/35f71bc0a09a45924bed268d8ccd0d3407bc476f

Read more...

【问题小解决】MySQL高可用集群之双主多从

通常MySQL主从复制主要用来解决读写分离,分担服务器压力。MySQL互为主备实现服务的高可用;这里同时基于高可用和负载均衡。

mysql-ha

环境准备

主机名/角色VIPIP地址操作系统MySQL版本
Node0/master1172.16.10.100172.16.10.10CentOS8.1.19118.0.17
Node1/master2172.16.10.11CentOS8.1.19118.0.17
Node2/slave1172.16.10.12CentOS8.1.19118.0.17

安装MySQL

在所有节点上执行dnf -y install mysql mysql-server,并在master节点上配置server-id并开启bin-log

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
vi /etc/my.cnf.d/mysql-server.cnf
[mysqld]
# 主数据库端ID号,全局唯一,通常用IP地址最后一位
server_id = 10
# 开启二进制日志
log-bin = mysql-bin
# 需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可
binlog-do-db = test
# 将从服务器从主服务器收到的更新记入到从服务器自己的二进制日志文件中
log-slave-updates
# 控制binlog的写入频率。每执行多少次事务写入一次(这个参数性能消耗很大,但可减小MySQL崩溃造成的损失)
sync_binlog = 1
# 下面这两个参数非常重要
# 这个参数一般用在主主同步中,用来错开自增值, 防止键值冲突,master2上面改为2
auto_increment_offset = 1
# 这个参数一般用在主主同步中,用来错开自增值, 防止键值冲突
auto_increment_increment = 2
# 二进制日志自动删除的天数,默认值为0,表示“没有自动删除”,启动时和二进制日志循环时可能删除
expire_logs_days = 7
# 将函数复制到slave
log_bin_trust_function_creators = 1

执行systemctl enable --now mysqld运行Mysql

Read more...