目录

Kubernets实战手册

参考资料

云原生技术的发展趋势正在朝着利用 Kubernetes 作为公共抽象层来实现高度一致的、跨云、跨环境的的应用交付而不断迈进。然而,尽管 Kubernetes 在屏蔽底层基础架构细节方面表现出色,它并没有在混合与分布式的部署环境之上引入上层抽象来为软件交付进行建模。我们已经看到,这种缺乏统一上层抽象的软件交付过程,不仅给降低了生产力、影响了用户体验,甚至还会导致生产中出现错误和故障。

今天,越来越多的应用研发团队期盼着这样一个平台:它既能够简化面向混合环境(多集群/多云/混合云/分布式云)的应用交付过程;同时又足够灵活可以随时满足业务不断高速变化所带来的迭代压力。然而,尽管平台团队很希望能帮上忙,但构建这样一个面向混合交付环境同时又高可扩展的应用交付系统,着实是一项令人生畏的任务。

KubeVela 通过以下设计,使得面向混合/多云环境的应用交付变得非常简单高效:

完全以应用为中心 - KubeVela 创新性的提出了开放应用模型(OAM)来作为应用交付的顶层抽象,并通过声明式的交付工作流来捕获面向混合环境的微服务应用交付的整个过程,甚至连多集群分发策略、流量调配和滚动更新等运维特征,也都声明在应用级别。用户无需关心任何基础设施细节,只需要专注于定义和部署应用即可。 可编程式交付工作流 - KubeVela 的交付模型是利用 CUE 来实现的。CUE 是一种诞生自 Google Borg 系统的数据配置语言,它可以将应用交付的所有步骤、所需资源、关联的运维动作以可编程的方式粘合成一个 DAG(有向无环图)来作为最终的声明式交付计划。相比于其他系统的复杂性和不可扩展性,KubeVela 基于 CUE 的实现不仅使用简单、扩展性极强,也更符合现代 GitOps 应用交付的趋势与要求。 基础设施无关 - KubeVela 是一个完全与运行时基础设施无关的应用交付与管理控制平面。所以它可以按照你定义的工作流与策略,面向任何环境交付和管理任何应用组件,比如:容器、云函数、数据库,甚至 网络和虚拟机实例等等。

视频教材

优化底层操作系统

数据中心的网络架构

核心软件的选型

域名准备工作

DNS域名智能解析

CoreDNS性能优化

CoreDNS是一款新型的dns权威服务器

软件名定位优点缺点
bind/powerdns权威dns,
包括NS,A,CNAME,PTR,TXT
可靠稳定,功能强大代码古老,配置繁琐,性能不高
dnsmasq缓存dns,
包括A,CNAME,TXT
配置简单,可靠稳定不能rewrite,性能不高
unbound缓存dns,
包括A
配置简单,性能高,支持tcp查询可靠稳定(没测试),不能CNAME
coredns权威dns,
包括NS,A,CNAME,PTR,TXT
配置超简单,可靠稳定,
性能高,无依赖(go)
支持插件体系,
支持etcd作为数据库条目
暂无

coredns.conf

.:253 {
  errors
  log stdout
  health localhost:8080
  cache {
        success 30000 300
        denial 1024 5
        prefetch 1 1m
  }
  loadbalance round_robin
 
  #新增以下一行Template插件,将AAAA记录类型拦截,返回空(NODATA)
  template IN AAAA .
 
  rewrite continue {
        ttl regex (.*) 180
  }
 
  rewrite stop name regex ^robin.x.upyun.com gw1.service.upyun answer name gw1.service.upyun robin.x.upyun.com
 
  rewrite stop {
      name regex ^(kuzan|vivi|slardar|rds).upyun.local {1}.service.upyun
      answer name ^(kuzan|vivi|slardar|rds).service.upyun {1}.upyun.local
  }
 
  file /opt/coredns/upyun.local.zone upyun.local
 
  proxy cdnlog-cn-hangzhou.aliyuncs.com 211.140.13.188 211.140.188.188
 
  proxy service.upyun 192.168.13.250:8600 192.168.13.230:8600 {
      policy sequential
      fail_timeout 1s
      max_fails 3
      spray
      protocol dns
  }
 
  forward .  119.29.29.29 180.76.76.76 114.114.114.114 {
      policy round_robin
      health_check 5s
      retry_failed 3
      except upyun.local service.upyun
  }
}

upyun.local.txt

$TTL 10
@     IN  SOA     ns1.upyun.local. root.upyun.local. (
            2   ;serial
            300 ; refresh
            1800 ; retry
            10  ; expire
            300 ; minimum
)
 
; used by haiyang.shao for apisix 
updc6   IN  CNAME   api
 
; used by shaohy for apisix gw1
api 10 IN A 192.168.5.91
api 10 IN A 192.168.5.92
api 10 IN A 192.168.5.93
api 10 IN A 192.168.5.94

DNS UDP负载均衡

upstream dns_load {
    server 192.168.13.229:253 weight=10 max_fails=5 fail_timeout=1s;
    server 192.168.13.230:253 weight=10 max_fails=5 fail_timeout=1s;
    server 192.168.13.231:253 weight=10 max_fails=5 fail_timeout=1s;
    server 192.168.144.1:253 weight=10 max_fails=5 fail_timeout=1s backup;
    server 192.168.144.2:253 weight=10 max_fails=5 fail_timeout=1s backup;
    server 192.168.144.3:253 weight=10 max_fails=5 fail_timeout=1s backup;
}
 
server {
    listen 192.168.21.20:53 udp;
    proxy_pass  dns_load;
    proxy_timeout   30s;
    proxy_connect_timeout   30s;
    access_log  logs/dns_access.log  main;
}
防止产生大并发查询卡顿

net.ipv4.tcpfintimeout=5
net.netfilter.nfconntrackmax=3000000

域名注册

★域名到期续费提醒
★备案到期提醒

NTP 时间服务器

upstream ntpd_load {
    server ntp.aliyun.com:123  weight=5 max_fails=2 fail_timeout=5s;
    server ntp.ntsc.ac.cn:123  weight=5 max_fails=2 fail_timeout=5s;
    server asia.pool.ntp.org:123 weight=5 max_fails=2 fail_timeout=5s;
    server ntp1.aliyun.com:123 weight=5 max_fails=2 fail_timeout=5s backup;
}
 
server {
    listen 192.168.21.20:123 udp;
    proxy_pass  ntpd_load;
    proxy_timeout   30s;
    proxy_connect_timeout   30s;
}
内网重要组件,也可以使用nginx或者apisix的stream proxy来代理

APISIX的部署和使用

sudo yum install -y https://repos.apiseven.com/packages/centos/apache-apisix-repo-1.0-1.noarch.rpm
yum install -y apisix apisix-dashboard
 
apisix init_etcd
apisix init
systemctl start apisix
systemctl enable apisix
 
systemctl start apisix-dashboard
systemctl enable apisix-dashboard

配置stream和http代理

apisix:
  enable_admin: true
  stream_proxy: # TCP/UDP proxy
    udp: # UDP proxy address list
      - 192.168.12.19:53
      - 192.168.12.19:123
      - 192.168.12.19:8600
 
discovery:
  consul:
    servers:
      - "http://192.168.13.229:8500"
      - "http://192.168.13.230:8500"
      - "http://192.168.13.231:8500"
 
deployment:
  role: traditional
  role_traditional:
    config_provider: etcd
  etcd:
    use_grpc: true
    timeout: 3600
    host:
      - "http://127.0.0.1:2379"
    prefix: "/apisix"

注册tcp/udp代理

curl http://127.0.0.1:9180/apisix/admin/stream_routes/2 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "server_addr": "192.168.12.19",
    "server_port": 123,
    "upstream": {
        "nodes": {
            "ntp.aliyun.com:123": 1,
            "ntp.ntsc.ac.cn:123": 1,
            "asia.pool.ntp.org:123": 1
        },
        "type": "roundrobin"
    }
}'
 
curl http://127.0.0.1:9180/apisix/admin/stream_routes/3 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "server_addr": "192.168.12.19",
    "server_port": 8600,
    "upstream": {
        "nodes": {
            "192.168.13.229:8600": 1,
            "192.168.13.230:8600": 1,
            "192.168.13.231:8600": 1,
            "192.168.13.232:8600": 1,
        },
        "type": "roundrobin"
    }
}'

TLS证书加密

CDN加速

操作系统优化和升级

高可用数据库与分布式

Ansible自动化部署K8S

K8S的技术优势

Kubernetes master集群部署

leader-elect=true自选举,竞争上岗

Kube-proxy工作机制

ServiceIP (iptables)

kube-router工作原理

IPVS + IPSET

高可用Kubernets控制平面

K8S最小服务器规范
  • kube-router与交换机用 ospf 或者 lvs
  • kube-nodes就弹性扩展就好了

系统安装/优化/安全

sysctl.conf优化

#hash: v0.1.1-30b3ffd                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
kernel.core_uses_pid=1
kernel.pid_max=4194303
kernel.ctrl-alt-del=1
 
kernel.msgmnb=65536
kernel.msgmax=65536
kernel.shmmni=4096
kernel.shmmax=8589934592
kernel.shmall=8589934592
kernel.sem=250 32000 100 128
 
# Increase number of incoming connections.max=65535
net.core.somaxconn=8192
net.core.rmem_default=131072
net.core.wmem_default=131072
net.core.rmem_max=33554432
net.core.wmem_max=33554432
net.core.dev_weight=512
net.core.optmem_max=262144
net.core.netdev_budget=1024
net.core.netdev_max_backlog=262144
 
net.ipv4.neigh.default.gc_thresh1=10240
net.ipv4.neigh.default.gc_thresh2=40960
net.ipv4.neigh.default.gc_thresh3=81920
 
# for lvs tunnel mode
net.ipv4.conf.all.proxy_arp=0
 
# http://blog.clanzx.net/2013/10/30/arp-filter.html
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.default.arp_announce=2
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.default.arp_ignore=1
net.ipv4.conf.all.arp_filter=1
net.ipv4.conf.default.arp_filter=1
 
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.rp_filter=0
 
# https://mellowd.co.uk/ccie/?tag=pmtud
# Warning,if MTU=9000 set 1, else 0 is good
net.ipv4.tcp_mtu_probing=0
net.ipv4.ip_no_pmtu_disc=0
 
net.ipv4.tcp_slow_start_after_idle=0
# Do not cache metrics on closing connections
net.ipv4.tcp_no_metrics_save=1
# Protect Against TCP Time-Wait
net.ipv4.tcp_rfc1337=1
 
net.ipv4.conf.default.accept_source_route=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.default.secure_redirects=0
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.secure_redirects=0
 
net.ipv4.ip_forward=1
net.ipv4.ip_local_port_range=9000 65535
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.icmp_ignore_bogus_error_responses=1
 
net.ipv4.tcp_timestamps=1
net.ipv4.tcp_sack=1
net.ipv4.tcp_dsack=1
net.ipv4.tcp_window_scaling=1
net.ipv4.tcp_rmem=4096 102400 16777216
net.ipv4.tcp_wmem=4096 102400 16777216
#net.ipv4.tcp_mem=3145728 4194304 6291456
net.ipv4.tcp_mem=786432 1048576 1572864
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_syn_retries=3
net.ipv4.tcp_synack_retries=5
net.ipv4.tcp_retries1=3
net.ipv4.tcp_retries2=15
net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_max_syn_backlog=262144
net.ipv4.tcp_max_orphans=262144
 
net.ipv4.tcp_frto=2
net.ipv4.tcp_thin_dupack=0
net.ipv4.tcp_reordering=3
net.ipv4.tcp_early_retrans=3
 
net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_keepalive_time=30
net.ipv4.tcp_keepalive_intvl=10
net.ipv4.tcp_keepalive_probes=3
net.ipv4.tcp_max_tw_buckets=600000
net.ipv4.tcp_congestion_control=bbr
 
net.ipv4.netfilter.ip_conntrack_max=600000
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait=1
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait=1
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait=1
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established=15
 
net.netfilter.nf_conntrack_max=600000
net.netfilter.nf_conntrack_tcp_timeout_close_wait=1
net.netfilter.nf_conntrack_tcp_timeout_fin_wait=1
net.netfilter.nf_conntrack_tcp_timeout_time_wait=1
net.netfilter.nf_conntrack_tcp_timeout_established=15
 
vm.swappiness=0
vm.dirty_writeback_centisecs=9000
vm.dirty_expire_centisecs=18000
vm.dirty_background_ratio=5
vm.dirty_ratio=10
vm.overcommit_memory=1
vm.overcommit_ratio=50
vm.max_map_count=200000
 
fs.file-max=524288
fs.aio-max-nr=1048576

netfilter/iptables优化

禁用conntrack跟踪模块

blacklist iptable_nat
blacklist nf_nat
blacklist nf_conntrack
blacklist nf_conntrack_ipv4
blacklist nf_defrag_ipv4

用iptables禁用跟踪

iptables -t raw -A PREROUTING -p ALL -j NOTRACK
iptables -t raw -A OUTPUT -p ALL -j NOTRACK

关闭默认firewalld启动iptables并清除默认规则

systemctl stop firewalld
systemctl disable firewalld
systemctl start iptables
systemctl enable iptables
iptables -F
service iptables save
 
[root@k8s-master ~]# firewall-cmd --permanent --add-port=6443/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=2379-2380/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10250/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10251/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10252/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10255/tcp
[root@k8s-master ~]# firewall-cmd --reload
[root@k8s-master ~]# modprobe br_netfilter
[root@k8s-master ~]# echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables

分布式存储Ceph

分布式存储MinIO

容器准备Mesos/K8S

Docker切换国内镜像下载源

修改Docker配置文件/etc/default/docker如下:

DOCKER_OPTS="--registry-mirror=http://aad0405c.m.daocloud.io"

修改Docker.service允许FORWARD为ACCEPT

ExecStartPost=/sbin/iptables -I FORWARD -s 0.0.0.0/0 -j ACCEPT

🏆Docker好用的镜像收集

etcd 集群部署

# 编辑配置文件
vim /etc/etcd/etcd.conf
# 样例配置如下
 
# 节点名称
ETCD_NAME=etcd0
# 数据存放位置
ETCD_DATA_DIR="/var/lib/etcd/etcd0"
# 监听其他 Etcd 实例的地址
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
# 监听客户端地址
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"
# 通知其他 Etcd 实例地址
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.154:2380"
# 初始化集群内节点地址
ETCD_INITIAL_CLUSTER="etcd0=http://192.168.1.154:2380,etcd1=http://192.168.1.156:2380,etcd2=http://192.168.1.249:2380"
# 初始化集群状态,new 表示新建
ETCD_INITIAL_CLUSTER_STATE="new"
# 初始化集群 token
ETCD_INITIAL_CLUSTER_TOKEN="mritd-etcd-cluster"
# 通知 客户端地址
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.154:2379,http://192.168.1.154:4001"

集群搭建好后,在任意节点执行

etcdctl member list 可列所有集群节点信息
etcdctl cluster-health 检查集群健康状态
如果以上命令出错,在日志报错出现:first record does not look like a TLS handshake

很有可能是查询的时候需要指定证书

etcdctl --ca-file /etc/kubernetes/ssl/ca.pem --endpoints "https://127.0.0.1:2379" cluster-health

etcd TLS 加密

如果日志报错出现:remote error: tls bad certificate, ServerName

原因是:ETCDCLUSTERNODE_LIST中的ip必须在生成etcd TLS证书时在etcd-csr.json中的hosts字段中指定(Subject Alternative Name(SAN)),否则可能会得到这样的错误。

etcd 备份和恢复

No help topic for 'snapshot'

ETCDCTL_API=3 etcdctl --endpoints=https://192.168.13.137:2379 snapshot save etcd_2022_11_18_10.db

Error: context deadline exceeded

ETCDCTL_API=3 etcdctl --endpoints=https://192.168.13.137:2379 snapshot save etcd_2022_11_18_10.db \
        --cacert /etc/kubernetes/ssl/ca.pem \
        --cert /etc/kubernetes/ssl/etcd.pem \
        --key /etc/kubernetes/ssl/etcd-key.pem

恢复操作

ETCDCTL_API=3 etcdctl snapshot restore snapshot.db --name m3 --data-dir=/home/etcd_data
  1. 每个节点成员都应该使用相同的快照恢复
  2. 恢复后的文件需要修改权限为 etcd:etcd
  3. –name:重新指定一个数据目录,可以不指定,默认为 default.etcd
  4. –data-dir:必须指定数据目录,并将 data-dir 对应于 etcd 服务中配置的 data-dir
在恢复时快照完整性的检验是可选的。如果快照是通过 etcdctl snapshot save 得到的,它将有一个被 etcdctl snapshot restore 检查过的完整性hash。如果快照是从数据目录复制而来,没有完整性hash,因此它只能通过使用 –skip-hash-check 来恢复。

kubectl常用命令

kubectl命令脑图

HTTP2加速

HTTP3/QUIC加速

QUIC协议在UDP层之上实现了可靠传输+加密,相当于HTTPS的TCP+TLS层 = HTTP3

Nginx 1.25.0版本将nginx-quic分支正式合入主线,标志着Nginx主线版本也可以支持IETF QUIC和HTTP/3协议。
  • HTTP/1.1 有两个主要的缺点:安全不足和性能不高。
  • HTTP/2 完全兼容 HTTP/1,头部压缩、多路复用等技术可以充分利用带宽,降低延迟,从而大幅度提高上网体验。但当出现了丢包时,HTTP/2 的表现反倒不如 HTTP/1 了。
  • QUIC (Quick UDP Internet Connections) 是HTTP/3中的底层支撑协议。该协议基于UDP,又汲取了TCP中的精华,实现了既快又可靠的协议。

nodePort,Port,targetPort之间的区别

这两个一般用在应用yaml描述文件中,起到的作用类似于docker -p选项

这两个一般用在service中,service 的类型为cluster ip时候:

这一个一般用在service中,service的类型为nodeport:

targetPort在pod上、负责与kube-proxy代理的port和Nodeport数据进行通信

nodePort,Port,targetPort之间的区别

🏆EasyKubernetes自动化部署

自动化部署的几种方式

准备ansible资源清单

[K8S]
k8s-m1 ansible_ssh_port=65422 ansible_ssh_host=192.168.13.134 ETCD="yes" K8S="both"
k8s-n2 ansible_ssh_port=65422 ansible_ssh_host=192.168.13.137 ETCD="yes" K8S="slave"
k8s-n3 ansible_ssh_port=65422 ansible_ssh_host=192.168.13.140 ETCD="yes" K8S="slave"

生成ssl证书

利用 mkssl.sh 生成证书:

  1. ca.pem, ca-key.pem
  2. etcd.pem, etcd-key.pem
  3. admin.pem, admin-key.pem
  4. k8s.pem(kube-apiserver) k8s-key.pem
  5. kube-controller.pem, kube-scheduler-key.pem
  6. kube-scheduler.pem, kube-controller-key.pem
  7. kube-proxy.pem, kube-proxy-key.pem

打包并解压

  K8S_SSL_Repo="http://devops.upyun.com/upyun.k8s.pem.tgz"
  tar zcvf upyun.k8s.pem.tgz etc/* ;  tar zxvf upyun.k8s.pem.tgz -C /

下载K8S对应的二进制版本

下载回来的二进制放在upyun.k8s.bin.tgz下重新打包

K8S_BIN_Repo="http://devops.upyun.com/upyun.k8s.bin.1.23.tgz"

初始化系统和docker环境

ansible-playbook -i lists_k8s main.yml -e "host=all" -t init

全新部署 etcd集群

ansible-playbook -i lists_k8s main.yml -e "host=all" -t etcd

全新部署kubernetes

ansible-playbook -i lists_k8s main.yml -e "host=all" -t k8s-bin,kube-router

检查kube-apiserver

  systemctl status kube-apiserver -l
  journalctl -xeu kube-apiserver
  grep "kube-apiserver: E" /var/log/messages
以上命令也适用其它组件的日志排查和定位

生成所需要的 *.kubeconfig

更名kubernetes配置重启组件

这个操作只需要在主节点机器上才要更名操作

配置kubectl子命令补全

yum install -y bash-completion
kubectl completion bash > ~/.kube/completion.bash.inc
source ~/.kube/completion.bash.inc
source ~/.bash_profile

检查所有组件的状态

kubectl get componentstatuses
kubectl describe nodes k8s-m1

检查csr并手动审批

kubectl get csr
kubectl certificate approve node-csr-xxxx
状态从 Pending → Approved → Issued
我们需要使用下面的命令为 Kubernetes 证书 API 创建一个证书签名请求。
  • 如果您设置例如 cert-manager 等外部签名者,则会自动批准证书签名请求(CSRs)
  • 否者,您必须使用 kubectl certificate 命令手动批准证书。

部署kube-router并检查所有节点状态

kubectl apply -f generic-kuberouter-all-features.yaml 
kubectl get nodes -o wide --all-namespaces

部署coredns容器内dns

kubectl apply -f coredns.yaml

K8S网络准备工作

Docker 网络通信

利用 Net Namespace 可以为 Docker 容器创建隔离的网络环境,容器具有完全独立的网络栈,与宿主机隔离。

我们在使用docker run创建 Docker 容器时,可以使用–network=选项指定容器的网络模式,Docker 有以下 4 种网络模式:

  1. host 模式,使用–network=host指定,不支持多主机;
  2. bridge 模式,使用–network=bridge指定,默认设置,不支持多主机;
  3. container 模式,使用–network=container:NAMEorID指定,即joiner 容器,不支持多主机;
  4. none 模式,使用–network=none指定,不支持多主机。

容器网络模型

更换网络模型时,一定要注意清理 /etc/cni/net.d/下的文件,避免冲突

交换机堆叠

网卡参数:BONDING_OPTS=“miimon=100 mode=2 xmit_hash_policy=1”

交换机OSPF

OSPF 的转发IP要跟交换机配置同步

K8S加密通讯部署

Kubernets各组件依赖的证书列表

★下发证书文件至所有节点(chmod -R 0755 /etc/kubernetes/ssl)

授权kubelet-bootstrap角色

kubectl create clusterrolebinding kubelet-bootstrap \
  --clusterrole=system:node-bootstrapper \
  --user=kubelet-bootstrap
 
kubectl create clusterrolebinding kubelet-bootstrap \
  --clusterrole=system:node-bootstrapper \
  --group=system:bootstrappers
 
kubectl create clusterrolebinding kubelet-nodes \
  --clusterrole=system:node \
  --group=system:nodes       
kubectl describe clusterrole system:kube-controller-manager
kubectl delete clusterrole system:kube-controller-manager

部署kube-controller-manager加密

创建 kube-controller-manager 证书和私钥

mkcontroller(){
cat > kube-controller-csr.json <<EOF 
{
  "CN": "kubernetes",
  "hosts": [
EOF
echo -en $HOST >> kube-controller-csr.json
cat >> kube-controller-csr.json <<EOF 
      "192.168.0.0/16",
      "kubernetes",
      "kubernetes.default",
      "kubernetes.default.svc",
      "kubernetes.default.svc.cluster",
      "kubernetes.default.svc.cluster.local"
    ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ZJ",
      "L": "HZ",
      "O": "system:kube-controller-manager",
      "OU": "$OU"
    }
  ]
}
EOF
 
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes  kube-controller-csr.json | cfssljson -bare kube-controller
}
将生成的证书和私钥 pem 分发到所有 master 节点.

创建和分发 kubeconfig 文件

# kube-controller-manager kubeconfig
# 设置集群参数
kubectl config set-cluster kubernetes \
      --certificate-authority=/etc/kubernetes/ssl/ca.pem \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=controller-manager.kubeconfig.${node_name}
 
# 设置客户端认证参数
kubectl config set-credentials system:kube-controller-manager \
      --client-certificate=/etc/kubernetes/ssl/kube-controller.pem \
      --client-key=/etc/kubernetes/ssl/kube-controller-key.pem  \
      --embed-certs=true \
      --kubeconfig=controller-manager.kubeconfig.${node_name}
 
# 设置上下文参数
kubectl config set-context system:kube-controller-manager \
      --cluster=kubernetes \
      --user=system:kube-controller-manager \
      --kubeconfig=controller-manager.kubeconfig.${node_name}
 
# 设置默认上下文
kubectl config use-context system:kube-controller-manager --kubeconfig=controller-manager.kubeconfig.${node_name}
将生成的证书和私钥 controller-manager.kubeconfig 分发到所有 master 节点.

创建 kube-controller-manager systemd unit 模板文件

K8S高级之监控系统

Kubernetes 集群的监控方案目前主要有以下几种方案:

不过 kube-state-metrics 和 metrics-server 之间还是有很大不同的,二者的主要区别如下:
  1. kube-state-metrics 主要关注的是业务相关的一些元数据,比如 Deployment、Pod、副本状态等
  2. metrics-server 主要关注的是资源度量 API 的实现,比如 CPU、文件描述符、内存、请求延时等指标。

监控对象包括:

比较合适的架构:

要监控交换机需要安装snmp_exporter代理节点,这个节点可以放在任意一台服务器上,前提是 snmp 节点服务器能和交换机通信,还能与 prometheus 主服务器之间通信。
#kubelet cAdvisor 默认在所有接口监听 4194 端口的请求, 以下iptables限制内网访问
ExecStartPost=/sbin/iptables -A INPUT -s 172.30.0.0/16 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -s 172.16.0.0/16 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -s 192.168.0.0/16 -p tcp --dport 4194 -j ACCEPT
ExecStartPost=/sbin/iptables -A INPUT -p tcp --dport 4194 -j DROP

prometheus的特点

和其他监控系统相比,Prometheus的特点包括:

prometheus相关组件

Prometheus生态系统由多个组件组成,其中许多是可选的:

promethues 的各个组件基本都是用 golang 编写,对编译和部署十分友好.并且没有特殊依赖.基本都是独立工作

Prometheus安装

wget https://github.com/prometheus/prometheus/releases/download/v2.9.2/prometheus-2.9.2.linux-amd64.tar.gz
tar zxvf prometheus-2.9.2.linux-amd64.tar.gz 
mv prometheus-2.9.2.linux-amd64 /opt/prometheus
 
useradd -m -d /var/lib/prometheus -s /sbin/nologin prometheus
chown -R prometheus:prometheus /opt/prometheus

vi /etc/profile.d/prometheus.sh

export PATH=$PATH:/opt/prometheus

vi /etc/systemd/system/prometheus.service

[Unit]
Description=Prometheus Server
Documentation=https://prometheus.io/docs/introduction/overview/
After=network-online.target
 
[Service]
User=prometheus
Group=prometheus
Restart=on-failure
ExecStart=/opt/prometheus/prometheus \
  --config.file=/opt/prometheus/prometheus.yml \
  --storage.tsdb.path=/opt/prometheus/data \
  --storage.tsdb.retention.time=30d \
  --enable-feature=remote-write-receiver
 
[Install]
WantedBy=multi-user.target

机器安装:各种exporter,也可以自定义监控指标key

Prometheus热加载

  1.  kill -HUP pid
  2.  curl -X POST http://localhost:9090/-/reload

prometheus官方提供了一个非常贴心的工具,prometool 可以检查配置文件是否正确,用法:(其他用法自行开发)

./promtool check config prometheus.yml

node_exporter安装

docker安装node_exporter

docker run -tid --restart=always --name=node_exporter \
  --net="host" \
  --pid="host" \
  -v "/:/host:ro,rslave" \
  quay.io/prometheus/node-exporter \
  --path.rootfs /host

/etc/systemd/system/node_exporter.service

[Unit]
Description=Node_exporter
DefaultDependencies=no
 
[Service]
Type=simple
User=node_exporter
RemainAfterExit=yes
ExecStart=/opt/node_exporter/node_exporter --collector.textfile.directory=/data/node_exporter/ --web.listen-address=:9100 #根据实际路径修改
Restart=on-failure
 
[Install]
WantedBy=multi-user.target

/etc/supervisor.d/node_exporter.conf

[program:node_exporter]
command = /opt/node_exporter/node_exporter
autostart = true
autorestart = true
stdout_logfile = NONE
stderr_logfile = NONE

prometheus.yml添加node_exporter监控项

  - job_name: 'node-exporter'
    static_configs:
    - targets: ['192.168.21.20:9100']
      labels:
        instance: vpn

ceph_exporter安装

docker run -tid --restart=always -v /etc/ceph:/etc/ceph -p=9128:9128 digitalocean/ceph_exporter

prometheus.yml添加ceph_exporter监控项

  - job_name: 'ceph-exporter'
    static_configs:
    - targets: ['192.168.146.11:9128','192.168.146.12:9128','192.168.146.13:9128','192.168.146.14:9128']
      labels:
        instance: ceph

snmp_exporter安装

snmp_exporter 默认的snmp版本为1,并且没有指定 Community。

需要修改一下为自己的适配配置

重新编译snmp.yml文件

yum install -y gcc gcc-g++ make 
yum install -y net-snmp net-snmp-utils net-snmp-libs net-snmp-devel
 
go get github.com/prometheus/snmp_exporter/generator
cd ${GOPATH-$HOME/go}/src/github.com/prometheus/snmp_exporter/generator
go build
make mibs

编写generator.yml加入

    version: 2  # SNMP version to use. Defaults to 2.
    auth:
      # Community string is used with SNMP v1 and v2. Defaults to "public".
      community: public
export MIBDIRS=mibs
./generator generate

/etc/systemd/system/snmp_exporter.service

[Unit]
Description=prometheus
After=network.target
 
[Service]
Type=simple
User=prometheus
ExecStart=/opt/snmp_exporter/snmp_exporter --config.file=/opt/snmp_exporter/snmp.yml
Restart=on-failure
 
[Install]
WantedBy=multi-user.target

测试snmp_exporter转发功能

curl 'http://安装snmp_exporter的机器的IP:9116/snmp?target=被监控交换机IP'

prometheus.yml添加snmp监控项

  - job_name: 'snmp'
    scrape_interval: 120s
    scrape_timeout: 120s
    static_configs:
    - targets:
      - 172.16.1.5  # 添加需要被监控交换机的ip
      labels:
        instance: h3c
        location: SAD
    metrics_path: /snmp
    params:
      module: [if_mib]  #指定使用snmp_exporter程序的 if_mib 模块
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 192.168.5.76:9116  #指定snmp_exporter监控节点的代理服务器ip

mysql_exporter安装

数据库用户授权

GRANT REPLICATION CLIENT, PROCESS ON *.* TO 'exporter'@'127.0.0.1' identified by 'upyun.com123';
GRANT SELECT ON performance_schema.* TO 'exporter'@'127.0.0.1';

使用docker方式运行

docker pull prom/mysqld-exporter
 
docker run -d \
  --net="host" \
  -e DATA_SOURCE_NAME="exporter:upyun.com123@(127.0.0.1:3306)/" \
  prom/mysqld-exporter

prometheus.yml添加mysql监控项

  - job_name: 'mysql-exporter'
    static_configs:
    - targets: ['192.168.144.109:9104']
      labels:
        instance: mysql

可以先用命令测试一下

curl http://192.168.144.109:9104/metrics

Grafana数据可视化

Grafana Dashboard 有着非常漂亮的图表和布局展示,功能齐全的度量仪表盘和图形编辑器,支持Graphite、zabbix、InfluxDB、Prometheus和OpenTSDB作为数据源。

Grafana主要特性:

Grafana安装

wget https://dl.grafana.com/oss/release/grafana-6.1.6.linux-amd64.tar.gz 
tar zxvf grafana-6.1.6.linux-amd64.tar.gz 
mv grafana-6.1.6 /opt/grafana

/etc/systemd/system/grafana.service

groupadd grafana
useradd -g grafana -m -d /var/lib/grafana -s /sbin/nologin grafana

/etc/sysconfig/grafana-server

GRAFANA_USER=grafana
GRAFANA_GROUP=grafana
GRAFANA_HOME=/opt/grafana
LOG_DIR=/var/log
DATA_DIR=/var/lib/grafana
MAX_OPEN_FILES=10000
CONF_DIR=/opt/grafana
CONF_FILE=/opt/grafana/conf/grafana.ini
RESTART_ON_UPGRADE=true
PLUGINS_DIR=/var/lib/grafana/plugins
PROVISIONING_CFG_DIR=/opt/grafana/conf/provisioning
# Only used on systemd systems
PID_FILE_DIR=/var/lib/grafana

/etc/systemd/system/grafana.service

ExecStart=/opt/grafana/bin/grafana-server                                           \
                            --homepath /opt/grafana                                 \
                            --config=${CONF_FILE}                                   \
                            --pidfile=${PID_FILE_DIR}/grafana-server.pid            \
                            cfg:default.paths.logs=${LOG_DIR}                       \
                            cfg:default.paths.data=${DATA_DIR}                      \
                            cfg:default.paths.plugins=${PLUGINS_DIR}                \
                            cfg:default.paths.provisioning=${PROVISIONING_CFG_DIR}

Grafana安装插件

如缺少插件则安装 饼图面板插件

for i in grafana-piechart-panel snuids-trafficlights-panel;do
  grafana-cli plugins install $i
done
 
 
vi /opt/grafana/conf/grafana.ini
... plugins = /data/grafana/plugins
systemctl restart grafana

Grafana报警配置

Grafana从4.0开始新增预警功能,下面简单介绍一下。Grafana告警设置分为两部分:

  1. Notification配置
  2. Alert配置

Notification配置:

其实就是配置告警途径,Grafana支持多种方式的告警:Email、webhook等。由于webhook比较通用,我们重点说下如何配置webhook。

Alert配置:

alert config页面设置报警阈值,和报警条件等。

alertmanager报警器

在某些情况下除了Alertmanager已经内置的集中告警通知方式以外,对于不同的用户和组织而言还需要一些自定义的告知方式支持。通过Alertmanager提供的webhook支持可以轻松实现这一类的扩展。除了用于支持额外的通知方式,webhook还可以与其他第三方系统集成实现运维自动化,或者弹性伸缩等。

wget https://github.com/prometheus/alertmanager/releases/download/v0.17.0/alertmanager-0.17.0.linux-amd64.tar.gz
tar zxvf alertmanager-0.17.0.linux-amd64.tar.gz 
mv alertmanager-0.17.0.linux-amd64 /opt/alertmanager

vi alertmanager.yml

global:
  resolve_timeout: 5m
route:
  receiver: webhook
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  group_by: [alertname]
  routes:
  - receiver: webhook
    group_wait: 10s
    match:
      team: node
receivers:
- name: webhook
  webhook_configs:
  - url: http://localhost:8060/dingtalk/webhook1/send 
    send_resolved: true
http://localhost:8060/dingtalk/webhook1/send

这个报警通道名称要一致!

vi /etc/systemd/system/alertmanager.service

[Unit]
Description=Alertmanager
After=network.target
 
[Service]
Type=simple
User=prometheus
ExecStart=/opt/alertmanager/alertmanager --config.file=/opt/alertmanager/alertmanager.yml --storage.path=/data/alertmanager
Restart=on-failure
 
[Install]
WantedBy=multi-user.target

alertmanager报警规则

Prometheus除了存储数据外,还提供了一种强大的功能表达式语言PromQL,允许用户实时选择和汇聚时间序列数据。

表达式的结果可以在浏览器中显示为图形,也可以显示为表格数据,或者由外部系统通过 HTTP API 调用。通过PromQL用户可以非常方便地查询监控数据,或者利用表达式进行告警配置

alertmanager集成钉钉

钉钉自定义“新内测报警”

13396815591/GeminisXXX
 
https://oapi.dingtalk.com/robot/send?access_token=0f0b2e4b29ccedbfa6ef2b609dbbc1dbda3aa074c4f198337acad55119f3cba5

用docker方式安装prometheus-webhook-dingtal

docker pull timonwong/prometheus-webhook-dingtalk
docker run -tid --restart=always --name dingtalk -p 8060:8060 timonwong/prometheus-webhook-dingtalk --ding.profile="webhook1=https://oapi.dingtalk.com/robot/send?access_token=token1"
ding.profile支持多个钉钉通道
webhook1= 这个名称要跟alertmanager配置中的名称一致

K8S高级之容器网络框架

更换网络模型时,一定要注意清理 /etc/cni/net.d/下的文件,避免冲突
ifconfig bond0 mtu 9000 up
ip link set dev bond0 mtu 9000

注意: 网络参数MTU在容器云跨机房互通上要协商一致(/sys/class/net/ethX/mtu),如 9000就需要设备一致.

Kube-router基于BGP和IPVS的网络框架

kube-router采用ipvs服务发现和实现svc网络,采用bgp实现pod网络,无需部署 kube-proxy 和 calico

kube-router也是基于cni网络

主要改进

负载均衡调度算法

Kube-router使用LVS作为服务代理。 LVS支持丰富的调度算法。您可以为该服务添加注释以选择一个调度算法。
当一个服务没有注释时,默认情况下选择“轮询”调度策略

For least connection scheduling use:
kubectl annotate service my-service "kube-router.io/service.scheduler=lc"
 
For round-robin scheduling use:
kubectl annotate service my-service "kube-router.io/service.scheduler=rr"
 
For source hashing scheduling use:
kubectl annotate service my-service "kube-router.io/service.scheduler=sh"
 
For destination hashing scheduling use:
kubectl annotate service my-service "kube-router.io/service.scheduler=dh"

Cilium基于eBPF和XDP的高性能网络框架

使用前的架构 使用BPF技术后的架构

转发效率对比

K8S高级之configmap和secret

redis-cli --cluster create --cluster-replicas 1 \
      10.109.218.140:6379 10.100.194.81:6379 \
      10.105.204.209:6379 10.97.40.13:6379   \
      10.108.48.154:6379 10.105.130.101:6379 \
      10.96.33.238:6379 10.97.154.41:6379 
 
redis-cli -c -h 10.109.218.140 -p 6379 cluster info

Secret介绍

Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用。

Secret类型

目前Secret的类型有3种:

  1. Opaque(default):任意字符串,base64编码格式的Secret,用来存储密码、密钥等;
  2. kubernetes.io/service-account-token:作用于ServiceAccount,就是kubernetes的Service Account中所说的。 即用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中;
  3. kubernetes.io/dockercfg: 作用于Docker registry,用户下载docker镜像认证使用。用来存储私有docker registry的认证信息。

Opaque Secret类型

#Opaque类型的数据是一个map类型,要求value是base64编码格式:
##创建admin账户
echo -n "admin" | base64
YWRtaW4=
echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm

ceph-config.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: ceph-web
provisioner: kubernetes.io/rbd
parameters:
  monitors: 192.168.146.11,192.168.146.12,192.168.146.13,192.168.146.14
  adminId: admin
  adminSecretName: ceph-secret
  adminSecretNamespace: lnmp
  pool: rbd
  userId: admin
  userSecretName: ceph-secret
  fsType: xfs
  imageFormat: "1"
  imageFeatures: "layering"
 
---
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret
  namespace: lnmp
type: "kubernetes.io/rbd"  
data:
  # 这个就是 ceph.client.admin.keyring中的key做 base64加密
  key: QVFESUQzTmEyeFcrTnhBQXlPdlYxZ0NwWHFqR0tlR29wdDYxNkE9PQ==

nginx-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config-vol
  namespace: lnmp
  labels:
    app: nginx
data:
  default.conf: |
    server {
      listen 80;
      server_name "";
 
      root /usr/html;
      index index.php index.html index.htm;
 
      error_page 404 /404.html;
      location = /40x.html {
      }
 
      error_page 500 502 503 504 /50x.html;
      location = /50x.html {
      }
 
      location ~.*.(js|css|html|png|jpg|gif|mp4|svg|apk|pbk)$ {
              expires 7d;
      }
 
      location ~ \.php$ {
              fastcgi_pass  php-svc:9000;
              fastcgi_index index.php;
              include fastcgi_params;
              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      }
    }

nginx-deployment.yaml

apiVersion: apps/v1beta1 # for versions before 1.8.0 use apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: lnmp
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: docker.io/smebberson/alpine-nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nfs-pv
          mountPath: /usr/html
        - name: config
          mountPath: /etc/nginx/conf.d
      volumes:
      # 宿主机上的目录
      - name: nfs-pv
        nfs:
          path: /mnt/nfs
          server: 192.168.13.142
      - name: config
        configMap:
          name: nginx-config-vol
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: lnmp
  labels:
    app: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30080

mysql-secret.yaml

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: mysql-secrets
  namespace: lnmp
  labels:
    app: mysql
data:
  #root
  root-password: dXB5dW4xMjM=
  #upyun123
  root-user: cm9vdA==

mysql-deployment.yaml

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: mysql
  namespace: lnmp
spec:
  serviceName: mysql-svc
  replicas: 3
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: copy-mariadb-config
        image: busybox
        command: ['sh', '-c', 'cp /configmap/* /etc/mysql/conf.d']
        volumeMounts:
        - name: configmap
          mountPath: /configmap
        - name: config
          mountPath: /etc/mysql/conf.d
      containers:
      - name: mysql
        image: ausov/k8s-mariadb-cluster
        ports:
        - containerPort: 3306
          name: mysql
        - containerPort: 4444
          name: sst
        - containerPort: 4567
          name: replication
        - containerPort: 4568
          name: ist
        env:
        - name: GALERA_SERVICE
          value: "mysql-svc"
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: root-password
        - name: MYSQL_ROOT_USER
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: root-user
        - name: MYSQL_INITDB_SKIP_TZINFO
          value: "yes"
        readinessProbe:
          exec:
            command: ["bash", "-c", "mysql -uroot -p\"${MYSQL_ROOT_PASSWORD}\" -e 'show databases;'"]
          initialDelaySeconds: 20
          timeoutSeconds: 5
        volumeMounts:
        - name: config
          mountPath: /etc/mysql/conf.d
        - name: datadir
          mountPath: /var/lib/mysql
      volumes:
      - name: config
        emptyDir: {}
      - name: configmap
        configMap:
          name: mysql-config-vol
          items:
            - path: "galera.cnf"
              key: galera.cnf
            - path: "mariadb.cnf"
              key: mariadb.cnf
  volumeClaimTemplates:
  - metadata:
      name: datadir
      annotations:
        volume.beta.kubernetes.io/storage-class: "ceph-web"
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
  name: mysql-svc
  namespace: lnmp
  labels:
    app: mysql
    tier: data
spec:
  selector:
    app: mysql
  ports:
  - port: 3306
    targetPort: 3306
    name: mysql
  clusterIP: None

K8S高级之YAML服务编写

参考资料

Kubernetes RBAC控制

参考资料

# kube-apiserver :  --authorization-mode=RBAC
 
kubectl create clusterrolebinding kubelet-node-clusterbinding --clusterrole=system:node --user=system:node:k8s-m1
kubectl get clusterrolebindings -o wide --all-namespaces

K8S高级之容器日志收集分析

参考资料

K8S高级之分布式埋点追踪

参考资料

分布式追踪系统发展很快,种类繁多,但核心步骤一般有三个:代码埋点,数据存储、查询展示。

K8S高级之持久化存储

参考资料

Ceph & MySQL

yum install -y ceph-common # 每个节点都要安装

failed to create rbd image

rbd: extraneous parameter

获取pvc信息

kubectl get pvc --all-namespaces |awk '/pvc-/{print $4}' > xx
 
#!/bin/sh
while read LINE;do
        echo $LINE
        rbd info kubernetes-dynamic-$LINE
done < xx

K8S高级之弹性感知+水平扩展

参考资料

K8S高级之服务注册发现/负载均衡

服务自动注册/检测

服务自动发现

For non-RBAC deployments, you'll need to edit the resulting yaml before applying it:

  1. Remove the line serviceAccountName: coredns from the Deployment section.
  2. Remove the ServiceAccount, ClusterRole, and ClusterRoleBinding sections.

服务负载均衡

将 Nginx 或 HAProxy 部署到 Kubernetes 可将 Nginx 或 HAProxy 作为 ReplicaSet 或 DaemonSet(指定 Nginx 或 HAProxy 容器映像)部署到 Kubernetes。 使用 ConfigMap 存储代理的配置文件,然后将 ConfigMap 装载为卷。 创建 LoadBalancer 类型的服务,以通过 Azure 负载均衡器公开网关。

另外,请考虑在群集中的一组专用节点上运行网关。 这种做法的好处包括:

  • 隔离。 所有入站流量将转到可与后端服务相隔离的固定一组节点。
  • 稳定的配置。 如果网关配置不当,则整个应用程序可能不可用。
  • 性能。 出于性能原因,可能需要对网关使用特定的 VM 配置。
Traefik V2.1是一款比Nginx更方便的开源反向代理与负载均衡工具。它最大的优点是能够与常见的微服务系统直接整合,可以实现自动化动态配置。目前支持Docker、Swarm、Mesos/Marathon、 Mesos、Kubernetes、Consul、Etcd、Zookeeper、BoltDB、Rest API等等后端模型。

Traefik 兼容所有主流的集群技术

K8S高级之CRD构建服务

Operator模式

🏆K8S生态之kubevela实战

K8应用部署计划

KubeVela 围绕着云原生应用交付和管理场景展开,背后的应用交付模型是 Open Application Model,简称 OAM

KubeVela 的核心是将应用部署所需的所有组件和各项运维动作,描述为一个统一的、与基础设施无关的“部署计划”,进而实现在混合环境中标准化和高效率的应用交付。这使得最终用户无需关注底层细节,就可以使用丰富的扩展能力,并基于统一的概念自助式操作。

kubevela model

每一个应用部署计划都由四个部分组成,分别是组件制品、运维能力、部署策略和工作流。其格式如下:

  • 组件制品(Component): 组件定义一个应用包含的待交付制品(二进制、Docker 镜像、Helm Chart…)或云服务。我们认为一个应用部署计划部署的是一个微服务单元,里面主要包含一个核心的用于频繁迭代的服务,以及一组服务所依赖的中间件集合(包含数据库、缓存、云服务等),一个应用中包含的组件数量应该控制在约 15 个以内。
  • 运维特征(Trait): 运维特征是可以随时绑定给待部署组件的、模块化、可拔插的运维能力,比如:副本数调整(手动、自动)、数据持久化、 设置网关策略、自动设置 DNS 解析等。
  • 应用策略(Policy): 应用策略负责定义指定应用交付过程中的策略,比如多集群部署的差异化配置、资源放置策略、安全组策略、防火墙规则、SLO 目标等。
  • 工作流步骤(Workflow Step): 工作流由多个步骤组成,允许用户自定义应用在某个环境的交付过程。典型的工作流步骤包括人工审核、数据传递、多集群发布、通知等。

helm安装及配置

helm repo add kubevela https://charts.kubevela.net/core
helm repo update
helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wait --set multicluster.enabled=false
 
# vela addon disable velaux
# vela uninstall
# helm uninstall -n vela-system kubevela
# kubectl get crd |grep oam | awk '{print $1}' | xargs kubectl delete crd
# rm -rf ~/.vela
报错日志: waiting for cluster gateway service: ClusterGateway
参考这个资料:“Cluster Gateway”用于将 kubernetes api流量路由到多个kubernetes 集群,可以使用: –set multicluster.enabled=false禁用

Helm Chart CICD

交付第一个应用

# 此命令用于在管控集群创建命名空间
vela env init prod --namespace prod
 
vela up -f https://kubevela.net/example/applications/first-app.yaml
vela delete first-vela-app
 
 
#正常情况下应用完成第一个目标部署后进入暂停状态(workflowSuspending)。
vela status first-vela-app
 
#人工审核,批准应用进入第二个目标部署
vela workflow resume first-vela-app
 
#通过下述方式来访问该应用
vela port-forward first-vela-app 8000:8000
 
curl http://127.0.0.1:8000
 
 
<pre>
Hello KubeVela! Make shipping applications more enjoyable. 
 
 
                                   ,
                                   //,
                                   ////
                               ./  /////*
                             ,///  ///////
                           ./////  ////////
                          ///////  /////////
                         ////////  //////////
                       ,/////////  ///////////
                      ,//////////  ///////////.
                     .///////////  ////////////
                     ////////////  ////////////.
                    *////////////  ////////////*
       #@@@@@@@@@@@*     ..,,***/  /////////////
        /@@@@@@@@@@@#
         *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&
          .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
 
              @@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                .&@@@*    *@@@&    ,@@@&.
 
       _  __       _          __     __     _
      | |/ /_   _ | |__    ___\ \   / /___ | |  __ _
      | ' /| | | || '_ \  / _ \\ \ / // _ \| | / _` |
      | . \| |_| || |_) ||  __/ \ V /|  __/| || (_| |
      |_|\_\\__,_||_.__/  \___|  \_/  \___||_| \__,_|

first-app.yaml

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: first-vela-app
spec:
  components:
    - name: express-server
      type: webservice
      properties:
        image: oamdev/hello-world
        ports:
         - port: 8000
           expose: true
      traits:
        - type: scaler
          properties:
            replicas: 1
  policies:
    - name: target-default
      type: topology
      properties:
        # local 集群即 Kubevela 所在的集群
        clusters: ["local"]
        namespace: "default"
    - name: target-prod
      type: topology
      properties:
        clusters: ["local"]
        # 此命名空间需要在应用部署前完成创建
        namespace: "prod"
    - name: deploy-ha
      type: override
      properties:
        components:
          - type: webservice
            traits:
              - type: scaler
                properties:
                  replicas: 2
  workflow:
    steps:
      - name: deploy2default
        type: deploy
        properties:
          policies: ["target-default"]
      - name: manual-approval
        type: suspend
      - name: deploy2prod
        type: deploy
        properties:
          policies: ["target-prod", "deploy-ha"]

K8S高级之Knative函数服务

K8S高级之ServiceMesh - Maesh实践

Maesh与Kubernetes本机集成,可以使用Helm安装。Maesh需要Kubernetes 1.11或更高版本,因为它利用CoreDNS来运行Maesh端点,而不是标准Kubernetes服务端点。Maesh端点与服务并排运行,并且默认情况下是选择加入的。在将现有服务添加到网格之前,它们不会受到影响,从而可以将Maesh逐步集成到应用程序中。

Maesh功能集建立在Golang开源反向代理和负载均衡器Traefik之上,包括Traefik的核心组件。网络可观察性通过OpenTracing实现,OpenTracing是供应商中立的API规范和用于分布式跟踪的工具框架。诸如负载平衡,重试,断路器和速率限制之类的流量管理控件可以定义为Kubernetes服务上的注释。

Maesh还支持使用SMI(服务网格技术的标准接口)进行配置。当在SMI模式下配置Maesh时,将明确启用访问和路由。默认情况下,所有路由和访问都被拒绝。启用S​​MI 是安装服务网格时定义的Maesh 静态配置的一部分。

Maesh同时支持TCP和HTTP。在HTTP模式下,Maesh依靠Traefik在虚拟主机,路径,标头,cookie上启用路由。使用TCP模式可以与SNI路由支持集成。在单个群集中可以同时使用两种模式。

若要使用Maesh,请不要将服务引用为<servicename>.<namespace>,而是将服务引用为<servicename>.<namespace> .maesh。 这些引用将通过Maesh服务网格访问和路由请求。通过这种方法,一些服务可以通过服务网格运行,而其他服务则不需要。

Maesh rbac角色创建

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system

Maesh需要本地存储

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-path
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
 
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-storage
spec:
  capacity:
    storage: 1Gi
  # volumeMode field requires BlockVolume Alpha feature gate to be enabled.
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - k8s-m1
          - k8s-n2
          - k8s-n3

Maesh Helm包安装

helm repo add maesh https://containous.github.io/maesh/charts
helm repo update
helm init --service-account tiller
helm list
helm del --purge maesh
helm install --name=maesh --namespace=maesh maesh/maesh
 
kubectl -n kube-system get pods,deployment,svc
kubectl get all -n maesh
 
kubectl delete deployment tiller-deploy --namespace=kube-system
kubectl delete svc tiller-deploy --namespace=kube-system

Maesh 实例

K8S高级之ServiceMesh服务治理

服务网格是一个专门的基础设施层,用来处理服务到服务之间的通信。服务网格用来解决微服务运维方面的一些复杂性,它围绕可观测性、重试/超时、服务发现以及动态代理等方面的最佳实践进行了封装,上述所提及的这些关注点通常会妨碍微服务的部署。

服务网格领域的几个流行工具包括:IstioLinkerd2CiliumConsul Connect

通过Service Mesh的控制平面,控制范围从微服务体系扩展到了API Gateway体系

将API Gateway纳入Service Mesh体系

参考资料

istio依赖socat:
socat是一个多功能的网络工具,支持广播和多播、抽象Unix sockets、Linux tun/tap、GNU readline 和 PTY。
socat的主要特点就是在两个数据流之间建立通道;且支持众多协议和链接方式:ip, tcp, udp, ipv6, pipe,exec,system,open,proxy,openssl,socket等。

istio手动加入sidecar

kubectl apply -f install/kubernetes/istio-demo.yaml

早期的做法

cd istio-0.7
kubectl create -f istio-sidecar-injector-configmap-release.yaml --dry-run -o=jsonpath='{.data.config}' > inject-config.yaml
kubectl -n istio-system get configmap istio -o=jsonpath='{.data.mesh}' > mesh-config.yaml
istioctl kube-inject \
    --injectConfigFile inject-config.yaml \
    --meshConfigFile mesh-config.yaml \
    --filename path/to/original/deployment.yaml \
    --output deployment-injected.yaml
kubectl apply -f deployment-injected.yaml

istio做内部域名测试

kubectl -n istio-system exec -ti prometheus -- nslookup istio-statsd-prom-bridge

istio做端口映射转发

grafana

kubectl -n istio-system port-forward \
  $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') \
  3000:3000 &
iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 3000 -j DNAT --to-destination 127.0.0.1:3000

servicegraph

kubectl -n istio-system port-forward \
  $(kubectl -n istio-system get pod -l app=servicegraph -o jsonpath='{.items[0].metadata.name}') \
  8088:8088 &
iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 8088 -j DNAT --to-destination 127.0.0.1:8088
 
http://192.168.13.142:8088/dotviz

istio直接使用iptables做转发

INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
 
 
src=`ip -4 route get 1.1.1.1|awk '/src/{print $NF}'`
kubectl get svc -n istio-system | awk '{ \
  if($1 ~ /grafana/ || $1 ~ /servicegraph/ || $1 ~ /jaeger-query/) { \
    gsub("/TCP","",$5);print "iptables -t nat -A PREROUTING -p tcp -d","'$src'","--dport",$5,"-j DNAT --to-destination",$3":"$5 \
  } \
}'

istio+bookinfo实践

istio+bookinfo实践

kubectl apply -f istio-demo.yaml 
kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml)
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml 
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

istio服务中的几个关键词

Gateway

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

DestinationRule

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3

VirtualService

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "*"
  gateways:
  - bookinfo-gateway
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 50
    - destination:
        host: reviews
        subset: v3
      weight: 50

🏆用Kubeadm搭建k8s集群

参考资料

初始化系统环境

ansible-playbook -i lists_k8s main.yml -e "host=all" -t init  # 初始化跟自动化脚本安装k8s的步骤一致
Kubernetes 1.8开始要求关闭系统的Swap,如果不关闭,默认配置下kubelet将无法启动。
可以通过kubelet的启动参数–fail-swap-on=false更改这个限制。
从 v1.10 开始,部分 kubelet 参数需在配置文件中配置 –kubeconfig=

导入仓库

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
        https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

安装工具

yum makecache fast
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet
ln -s /usr/libexec/docker/docker-runc-current /usr/local/bin/docker-runc  # 如果docker version <= 1.13

初始化安装

kubeadm reset # 先清理环境
 
kubeadm init \
  --kubernetes-version=v1.10.3 \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=0.0.0.0

状态检查

kubectl get cs
kubectl get csr
 
NAME                                                   AGE       REQUESTOR           CONDITION
node-csr-9mU9zhj0Q_OA3DyPeupKZrirTsOMLM0Ahl2Mjit6bEI   18m       kubelet-bootstrap   Approved,Issued
node-csr-HrGdN7amR0Vp1zSfvPFZMbD89U3R9nkHnVViCm-d_O8   18m       kubelet-bootstrap   Approved,Issued
node-csr-RPntnuINm2iVEYUKGSDLJHkyta9yq75mTZnFa_g9OaE   18m       kubelet-bootstrap   Approved,Issued
 
Approved = controller-manager没有配置好,检查是否加上了ssl授权
Approved,Issued = 确认授权 OK
kubectl get nodes -o wide
 
NAME      STATUS     ROLES     AGE       VERSION
k8s-m1    NotReady   <none>    1m        v1.11.0
k8s-n1    NotReady   <none>    1m        v1.11.0
k8s-n2    NotReady   <none>    1m        v1.11.0
 
NotReady  = nodes间的网络有问题
kubectl get pods -o wide --all-namespaces

配置pod network

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f  kube-flannel.yml
 
#kubectl apply -f http://mirror.faasx.com/kubernetes/installation/hosted/kubeadm/1.7/calico.yaml

master参与工作负载

kubectl taint nodes k8s-m1 node-role.kubernetes.io/master-

安装dashboard插件

用Weave Scope监控集群

使用kubeconfig文件配置跨集群认证

K8S常见问题集锦

定位问题命令

kubectl logs 
kubectl get events
kubectl describe pod

overlay2: the backing xfs without d_type

当Docker 运行在overlay2存储驱动上时,需要d_type特性的支持才能正常工作,Docker1.13以后加入了对此的检查,可以运行docker info命令来查看文件系统是否支持d_type这个特性

如果overlayfs存储驱动不支持d_type的话,容器在操作文件系统时可能会出现一些奇怪的错误:比如在bootstrap的时候出现Chown error,或者rebuild时发生错误等等。

mkfs.xfs -f -l internal,lazy-count=1,size=128m -i attr=2 -d agcount=8 -i size=512 -n ftype=1 /dev/vdb

docker-runc not installed on system

journalctl -xeu docker

ln -s /usr/libexec/docker/docker-runc-current /usr/local/bin/docker-runc
如果是使用docker 1.13之前的版本,需要做 docker-runc的软链

no API token found for service account

修改/etc/kubernetes/apiserver文件中KUBEADMISSIONCONTROL参数。

KUBE_ADMISSION_CONTROL="--admission_control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"

去掉“ServiceAccount”选项。

重启kube-apiserver服务

# systemctl restart kube-apiserver。

SecurityContext.RunAsUser is forbidden

修改/etc/kubernetes/apiserver文件中KUBEADMISSIONCONTROL参数。

KUBE_ADMISSION_CONTROL="--admission_control=NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota"

去掉“SecurityContextDeny”选项。

重启kube-apiserver服务

# systemctl restart kube-apiserver。

localhost:8080 was refused

注意到kube-apiserver的选项–insecure-port=0,也就是说kubeadm 1.6.0初始化的集群,kube-apiserver没有监听默认的http 8080端口。

所以我们使用kubectl get nodes会报

The connection to the server localhost:8080 was refused - did you specify the right host or port?。

查看kube-apiserver的监听端口可以看到只监听了https的6443端口,

为了使用kubectl访问apiserver,在~/.bashprofile中追加下面的环境变量: export KUBECONFIG=/etc/kubernetes/admin.conf source ~/.bashprofile 此时kubectl命令在master node上就好用了

pod服务一直处于ContainerCreating(先排除被墙)

# kubectl get pod 
# kubectl describe pod

通过日志排查,发现没有rhsm,尝试安装yum install rhsm ,不使用redhat的pause镜像,就没有这个问题。

User cannot create resource "certificatesigningrequests" in API group "certificates.k8s.io" at the cluster scope

kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers
如果还是不行的话,先删除之前旧的,再运行上述命令一次重新生成
kubectl delete clusterrolebinding kubelet-bootstrap 
 
 
[root@k8s-m1 kubernetes]# kubectl get csr -o wide --all-namespaces 
NAME                                                   AGE   REQUESTOR                 CONDITION
node-csr-TgFxbCj01ebWz-JQEwrMT5_IAa76Mg5GqgYdPvp2dT8   84s   system:bootstrap:c7i6gd   Pending

User cannot list resource "nodes" in API group "" at the cluster scope

少了角色, 需要加角色

kubectl create clusterrolebinding kubelet-nodes --clusterrole=system:node --group=system:nodes

csr证书状态一直为Pending

基于安全性考虑,CSR approving controllers 不会自动 approve kubelet server 证书签名请求,需要手动 approve:

kubectl certificate approve node-csr-TgFxbCj01ebWz-JQEwrMT5_IAa76Mg5GqgYdPvp2dT8

kubectl node01 notready

检查/etc/resolve.conf,检查master是否能够连通?

Unable to update cni config: No networks found

journalctl -xeu kubelet

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f  kube-flannel.yml

或者运行kube-router

kubectl apply -f https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kube-router-all-service-daemonset.yaml
检查kuber-apiserver启动参数中的token.csv和kubelet启动参数中指定的bootstrap文件bootstrap.kubeconfig中的token值是否一致,此外该token必须为实际数值,不能使用变量代替。

network: no IP ranges specifie

Failed to get pod CIDR from CNI conf file

kubectl get pods -o wide --all-namespaces 
NAMESPACE     NAME                READY   STATUS             RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
kube-system   kube-router-pn5mn   0/1     CrashLoopBackOff   3          2m34s   192.168.13.136   k8s-n2   <none>           <none>
 
[root@k8s-m1 kube-router]# kubectl -n kube-system logs  kube-router-pn5mn
Failed to parse kube-router config: Failed to build configuration from CLI: Error loading config file "/var/lib/kube-router/kubeconfig": read /var/lib/kube-router/kubeconfig: is a directory
rm -rf /var/lib/kube-router/kubeconfig &&  touch /var/lib/kube-router/kubeconfig

unknown container "/system.slice/kubelet.service"

在kubelet中追加配置

--runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice

Failed to get system container stats for

failed to get cgroup stats for

failed to get container info for

–runtime-cgroups=/systemd/system.slice –kubelet-cgroups=/systemd/system.slice

kubernetes 1.9 与 CentOS 7.3 内核兼容问题

libcontainerd 推荐的 kernel 4.3 以上版本

kubernetes 1.9 与 Kernel内核兼容问题

  • kernel内核升级到 kernel-ml-5.4.5-1.el7.elrepo.x8664 * 新内核运行容器默认开启了net.ipv4.tcptimestamps,需要关闭

crictl not found in system path

手动安装一下 crictl 软件

kubectl get node No resources found

Failed to create ["kubepods"] cgroup

升级 systemd : yum update systemd

kubernetes如何删除nodes

kubectl delete node 10.31.31.29

pod status is Completed but not Succeeded

kubectl describe pod istio-cleanup-secrets -n istio-system
kubelet does not have ClusterDNS IP configured and cannot create Pod using “ClusterFirst” policy

Unable to authenticate ... invalid bearer token

检查kuber-apiserver启动参数中的token.csv和kubelet启动参数中指定的bootstrap文件bootstrap.kubeconfig中的token值是否一致,此外该token必须为实际数值,不能使用变量代替。

unable to do port forwarding: socat not found

yum install -y socat

如何安装高版本的docker

yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
 
yum list docker-ce.x86_64  --showduplicates |sort -r
 
yum install -y --setopt=obsoletes=0 \
  docker-ce-17.03.2.ce-1.el7.centos \
  docker-ce-selinux-17.03.2.ce-1.el7.centos

暂时停用某个节点

kubectl delete node xxx

调整某个节点的权重

给节点打标签label,区分不同类型资源
kubectl label node k8s-m1 cpu=high
kubectl label node k8s-n2 cpu=mid
kubectl label node k8s-n1 cpu=low
......
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: cpu
                operator: In
                values:
                - high
                - mid

迁移服务到别的节点

禁止pod调度到该节点上

kubectl cordon <node>

驱逐该节点上的所有pod

kubectl drain <node>

该命令会删除该节点上的所有Pod(DaemonSet除外),在其他node上重新启动它们,通常当该节点维护完成,启动了kubelet后,再使用

kubectl uncordon <node>

即可将该节点添加到kubernetes集群中。

统一修改pods的timezone

因此可以在编写kubernetes的yaml文件时添加如下内容,即可以将所有docker的时区配置为想要的

......
volumeMounts:
  - name: tz-config
    mountPath: /etc/localtime
......
volumes:
  - name: tz-config
    hostPath:
      path: /usr/share/zoneinfo/Asia/Shanghai

helm部署的权限问题

创建tiller用户角色

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system

删除旧的tiller-deploy

kubectl delete deployment tiller-deploy --namespace=kube-system
kubectl delete svc tiller-deploy --namespace=kube-system

重新初始化Helm并指定要使用的 Service Account

$ helm init --service-account tiller

local-path not found

local volume, 这是一个很新的存储类型,建议在k8s v1.10+以上的版本中使用。该local volume类型目前还只是beta版。

Local volume 允许用户通过标准PVC接口以简单且可移植的方式访问node节点的本地存储。 PV的定义中需要包含描述节点亲和性的信息,k8s系统则使用该信息将容器调度到正确的node节点。

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-path
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
 
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-storage
spec:
  capacity:
    storage: 1Gi
  # volumeMode field requires BlockVolume Alpha feature gate to be enabled.
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - k8s-m1
          - k8s-n2
          - k8s-n3

RunAsUser is forbidden

最简单的方法:

--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota,ServiceAccount,NodeRestriction

如何修改Kubernetes节点IP地址?

kubernetes 升级到1.24的笔记

Kubernetes 1.23 中可以使用 Docker Engine,但如果使用 Docker Engine 作为运行时,kubelet 启动时,会打印一个警告日志。您在 1.23 之前的所有版本中都会看到此警告。dockershim 将在 Kubernetes 1.24 移除。

unable to determine runtime API version docker

k8s1.24不支持docker作为运行时容器,需要采用containerd

使用containerd还是cri-o

为了更贴近OCI,k8s又搞了一个轻量级的容器运行时cri-o,所以在k8s“抛弃”dockershim后,可供我们选择的容器运行时有containerd和cri-o

小结一下kubelet启动容器的发展历程:
  1. 早期: kubelet → docker-manager → docker
  2. 中期: kubelet → CRI → docker-shim → docker → containerd → runc
  3. 中期: kubelet → CRI → cri-containerd → containerd → runc
  4. 当前: kubelet → CRI → containerd(CRI plugin) → runc
  5. 当前: kubelet → CRI → cri-o → runc

K8s 2.0展望