https://istio.io/docs/concepts

1、什么是Istio

云平台为使用它们的组织提供了很多好处。但是,不可否认的是,采用云技术会对DevOps团队造成压力。开发人员必须使用微服务来构建可移植性,同时运营商正在管理超大型混合和多云部署。Istio使您可以连接,保护,控制和观察服务。

从较高的角度来看,Istio有助于降低这些部署的复杂性,并减轻开发团队的负担。它是一个完全开源的服务网格,可以透明地分层到现有的分布式应用程序上。它也是一个平台,包括可将其集成到任何日志记录平台,遥测或策略系统中的API。Istio的多样化功能集使您能够成功,高效地运行分布式微服务架构,并提供一种统一的方式来保护,连接和监视微服务。

2、为什么要使用Istio

Istio可以轻松创建带有负载平衡,服务到服务的身份验证,监视等功能的已部署服务网络,而服务代码中的代码更改很少或没有更改。通过在整个环境中部署一个特殊的sidecar代理来拦截微服务之间的所有网络通信,然后使用其控制平面功能配置和管理Istio,可以为服务添加Istio支持,包括:

  • HTTP,gRPC,WebSocket和TCP通信的自动负载平衡。
  • 通过丰富的路由规则,重试,故障转移和故障注入对流量行为进行细粒度控制。
  • 可插拔的策略层和配置API,支持访问控制,速率限制和配额。
  • 集群内所有流量的自动度量,日志和跟踪,包括集群的入口和出口。
  • 通过强大的基于身份的身份验证和授权,在群集中进行安全的服务间通信。

Istio专为可扩展性而设计,可满足多种部署需求。

3、核心功能

Istio在服务网络中统一提供了许多关键功能:

3.1 流量管理

Istio的简单规则配置和流量路由使您可以控制服务之间流量和API调用的流。Istio简化了诸如断路器,超时和重试之类的服务级别属性的配置,并使其轻而易举地设置了重要任务(如A / B测试,canary部署和基于百分比的流量拆分的分阶段部署)。

借助对流量的更好可见性和开箱即用的故障恢复功能,无论遇到什么情况,您都可以在问题引起问题之前及时发现问题,使呼叫更加可靠,网络也更加强大。

流量管理概念指南:https://istio.io/docs/concepts/traffic-management/

3.2 安全

Istio的安全功能使开发人员可以将精力集中在应用程序级别上。Istio提供基础安全通信通道,并大规模管理服务通信的身份验证,授权和加密。借助Istio,默认情况下可以保护服务通信的安全,从而使您能够在各种协议和运行时之间一致地实施策略-所有这些操作几乎不需要更改应用程序。

尽管Istio是独立于平台的,但将其与Kubernetes(或基础架构)网络策略配合使用,其好处更大,包括能够在网络和应用程序层保护Pod到Pod或服务到服务的通信的能力。

安全性概念指南:https://istio.io/docs/concepts/security/

3.3 策略规定

Istio允许您为应用程序配置自定义策略,以在运行时强制执行规则,例如:

  • 速率限制以动态限制服务流量
  • 拒绝,白名单和黑名单,以限制对服务的访问
  • 标头重写和重定向

Istio还允许您创建自己的策略适配器,以添加例如自己的自定义授权行为。

策略概念指南:https://istio.io/docs/concepts/policies/

3.4 可观察性

Istio强大的跟踪,监视和日志记录功能使您可以深入了解服务网格部署。借助Istio的监视功能,可以真正了解服务性能如何影响上游和下游事物,而其自定义仪表板可提供对所有服务性能的可视性,并让您了解该性能如何影响您的其他流程。

Istio的Mixer组件负责策略控制和遥测收集。它提供了后端抽象和中介,使Istio的其余部分与各个基础架构后端的实现细节隔离开来,并为操作员提供了对网格和基础架构后端之间所有交互的精细控制。

所有这些功能使您可以更有效地设置,监视和实施服务上的SLO。当然,最重要的是您可以快速有效地检测和修复问题。

可观察性概念指南:https://istio.io/docs/concepts/observability/

3.5 平台支援

Istio是独立于平台的,旨在在多种环境中运行,包括跨Cloud,本地,Kubernetes,Mesos等的环境。您可以在Kubernetes或Consul的Nomad上部署Istio。Istio当前支持:

  • Kubernetes上的服务部署
  • 向领事注册的服务
  • 在单个虚拟机上运行的服务

3.6 集成和定制

Istio的策略执行组件可以扩展和定制,以与现有的ACL,日志记录,监视,配额,审核等解决方案集成。

1、简介

containerd是行业标准的容器运行时,重点是简单性,健壮性和可移植性。它可以作为Linux和Windows的守护程序使用,可以管理其主机系统的完整容器生命周期:图像传输和存储,容器执行和监控,低级存储和网络附件等。

容器化的设计旨在嵌入到更大的系统中,而不是由开发人员或最终用户直接使用。

cri是Kubernetes[容器运行时接口(CRI)的容器化插件实现

2、配置

containerd是一个可以在任何系统上运行的简单守护程序,配置文件的默认路径位于/etc/containerd/config.toml--config,-c引导守护程序时,可以通过标志更改此路径。

Containerd在主机系统上也有两个不同的存储位置。一种用于持久性数据,另一种用于运行时状态。

root将用于存储任何类型的容器持久化数据。快照,内容,容器和图像的元数据以及任何插件数据都将保留在此位置。根也为容器加载的插件命名空间。每个插件都有其自己的目录,用于存储数据。容器本身实际上并不需要存储任何持久性数据,它的功能来自于已加载的插件。

1
2
3
4
5
6
7
8
9
10
11
12
13
/var/lib/containerd/
├── io.containerd.content.v1.content
│ ├── blobs
│ └── ingest
├── io.containerd.metadata.v1.bolt
│ └── meta.db
├── io.containerd.runtime.v1.linux
│ ├── default
│ └── example
├── io.containerd.snapshotter.v1.btrfs
└── io.containerd.snapshotter.v1.overlayfs
├── metadata.db
└── snapshots

state将用于存储任何类型的临时数据。套接字,PID,运行时状态,安装点以及在重新启动之间不得保留的其他插件数据都存储在此位置。

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
/run/containerd
├── containerd.sock
├── debug.sock
├── io.containerd.runtime.v1.linux
│ └── default
│ └── redis
│ ├── config.json
│ ├── init.pid
│ ├── log.json
│ └── rootfs
│ ├── bin
│ ├── data
│ ├── dev
│ ├── etc
│ ├── home
│ ├── lib
│ ├── media
│ ├── mnt
│ ├── proc
│ ├── root
│ ├── run
│ ├── sbin
│ ├── srv
│ ├── sys
│ ├── tmp
│ ├── usr
│ └── var
└── runc
└── default
└── redis
└── state.json

3、插件

containerd在内部使用插件,以确保内部实现解耦,稳定并与外部插件平等对待。要查看容器中包含的所有插件,请使用ctr plugins ls

插件是使用[plugins]containerd的config部分配置的。每个插件都可以使用模式有其自己的部分[plugins.<plugin id>]

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
[plugins]
[plugins.cgroups]
no_prometheus = false
[plugins.cri]
stream_server_address = ""
stream_server_port = "10010"
enable_selinux = false
sandbox_image = "k8s.gcr.io/pause:3.5"
stats_collect_period = 10
systemd_cgroup = false
[plugins.cri.containerd]
snapshotter = "overlayfs"
[plugins.cri.containerd.default_runtime]
runtime_type = "io.containerd.runtime.v1.linux"
runtime_engine = ""
runtime_root = ""
[plugins.cri.containerd.untrusted_workload_runtime]
runtime_type = ""
runtime_engine = ""
runtime_root = ""
[plugins.cri.cni]
bin_dir = "/opt/cni/bin"
conf_dir = "/etc/cni/net.d"
[plugins.cri.registry]
[plugins.cri.registry.mirrors]
[plugins.cri.registry.mirrors."docker.io"]
endpoint = ["https://registry-1.docker.io"]

4、命令行工具

语法

1
ctr [global options] command [command options] [arguments...]

命令选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
plugins, plugin            提供关于容器插件的信息
version 打印客户端和服务器版本
containers, c, container 管理容器
content 管理内容
events, event 显示containerd事件
images, image, i 管理镜像
leases 管理租赁协定
namespaces, namespace, ns 管理名称空间
pprof 为containerd提供golang pprof输出
run 运行一个容器
snapshots, snapshot 管理快照
tasks, t, task 管理任务
install 安装一个新包
oci OCI工具
shim 直接与垫片互动
help, h 帮助

全局选项

1
2
3
4
5
--debug                      在日志中打开调试输出
--address value, -a value containerd的GRPC服务器地址(default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS]
--timeout value CTR命令总超时时间 (default: 0s)
--connect-timeout value 连接到containerd的超时(default: 0s)
--namespace value, -n value 与命令一起使用的命名空间(default: "default") [$CONTAINERD_NAMESPACE]

1、介绍

crictl 是 CRI 兼容的容器运行时命令行接口。 可以使用它来检查和调试 Kubernetes 节点上的容器运行时和应用程序。

2、安装

2.1 使用yum安装

安装containerd.io软件包就自带了crictl命令

1
2
3
4
5
yum install -y yum-utils
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
yum install -y containerd.io

2.2 使用二进制包

在github下载安装包:https://github.com/kubernetes-sigs/cri-tools/releases/tag/v1.21.0

1
2
3
4
VERSION="v1.21.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gz

3、设置配置文件

3.1 配置文件

crictl 默认连接到 unix:///var/run/dockershim.sock。 对于其他的运行时,可以用多种不同的方法设置端点:

  • 通过设置参数 --runtime-endpoint--image-endpoint
  • 通过设置环境变量 CONTAINER_RUNTIME_ENDPOINTIMAGE_SERVICE_ENDPOINT
  • 通过在配置文件中设置端点 --config=/etc/crictl.yaml

还可以在连接到服务器并启用或禁用调试时指定超时值,方法是在配置文件中指定 timeoutdebug 值,或者使用 --timeout--debug 命令行参数。

1
2
3
4
5
6
cat >> /etc/crictl.yaml << EOF    #这里使用containerd
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 3
debug: true
EOF

3.2 命令行

使用crictl config命令获取并设置crictl客户端配置选项

1
crictl config [command options] [<crictl options>]

例如,crictl config --set debug=true在提供后续crictl命令时将启用调试模式。

可选选项:

1
2
3
4
5
6
runtime-endpoint:       Container runtime endpoint
image-endpoint: Image endpoint
timeout: Timeout of connecting to server (default: 2s)
debug: Enable debug output (default: false)
pull-image-on-create: Enable pulling image on create requests (default: false)
disable-pull-on-run: Disable pulling image on run requests (default: false)

选项:

1
2
3
--get value  show the option value
--set value set option (can specify multiple or separate values with commas: opt1=val1,opt2=val2)
--help, -h show help (default: false)

启用后,pull-image-on-create将修改create container命令以首先拉出容器的映像。此功能用作帮助使创建容器更容易,更快的助手。crictl可能希望不要提取创建容器所需的图像。例如,图像可能已经被拉出或以其他方式加载到容器运行时中,或者用户可能在没有网络的情况下运行。因此,默认值forpull-image-on-create为false。

默认情况下,运行命令首先提取容器映像,并且disable-pull-on-run为false。的某些用户crictl可能希望将其设置disable-pull-on-run为true,以在使用run命令时默认情况下不拉取图像。

要覆盖这些默认的拉取配置设置,--no-pull--with-pull为create和run命令提供了选项。

4、用法

1
crictl [全局选项]命令[命令选项] [参数...]

指令

  • attach:附加到正在运行的容器
  • create:创建一个新的容器
  • exec:在正在运行的容器中运行命令
  • version:显示运行时版本信息
  • images:列出镜像
  • inspect:显示一个或多个容器的状态
  • inspecti:返回一个或多个镜像的状态
  • imagefsinfo:返回镜像文件系统信息
  • inspectp:显示一个或多个pods的状态
  • logs:获取容器的日志
  • port-forward:将本地端口转发到Pod
  • ps:列出容器
  • pull:从镜像库拉取镜像
  • runp:运行一个新的pod
  • rm:删除一个或多个容器
  • rmi:删除一个或多个镜像
  • rmp:删除一个或多个pod
  • pods:列出pods
  • start:启动一个或多个已创建的容器
  • info:显示容器运行时的信息
  • stop:停止一个或多个运行中的容器
  • stopp:停止一个或多个正在运行的Pod
  • update:更新一个或多个正在运行的容器
  • config:获取并设置crictl客户端配置选项
  • stats:列出容器资源使用情况统计信息
  • completion:输出bash shell完成代码
  • help, h:显示命令列表或一个命令的帮助

其他指令

  • --timeout-t:连接服务器的超时时间(以秒为单位)(默认值:10s)。0或更少将被解释为未设置并转换为默认值。没有设置超时值的选项,支持的最小超时为1s
  • --debug-D:启用调试输出
  • --help-h:显示帮助
  • --version-v:打印crictl的版本信息
  • --config-c:客户端配置文件的位置。如果未指定并且默认目录不存在,则也会搜索该程序的目录(默认目录:“ / etc / crictl.yaml”)[$ CRI_CONFIG_FILE]

5、创建pod报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@node2 ~]# cat pod-config.json
{
"metadata": {
"name": "sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}
[root@node2 ~]# crictl runp pod-config.json
FATA[0000] run pod sandbox failed: rpc error: code = Unknown desc = failed to setup network for sandbox "b20591a4fcb681975ed3f906de91455ad793f18dafc98630b23e64548ade90a6": pods "sandbox" not found

报错原因:calico daemonset监视apiserver以获取Pod列表,并根据Pod规范应用网络配置。自己使用沙盒,则apiserver上将没有相应的Pod,因此calico报告该错误。不建议用户运行crictl runscrictl create一个Kubernetes节点上,这些命令在那里只是一些特殊的调试情况。即使您能够创建沙箱,kubelet也将最终停止并删除它,因为它在apiserver上看不到相应的pod。

1、准备

  • 每台机器 2 GB 或更多的 RAM
  • 2 CPU 核或更多
  • 集群中的所有机器的网络彼此均能相互连接
  • 关闭selinux和firewalld
  • 关闭swap分区
  • 添加hosts解析

2、确保每个节点上 MAC 地址和 product_uuid 的唯一性

  • 使用命令 ip linkifconfig -a 来获取网络接口的 MAC 地址
  • 使用 cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验

一般来讲,硬件设备会拥有唯一的地址,但是有些虚拟机的地址可能会重复。 Kubernetes 使用这些值来唯一确定集群中的节点。

3、允许 iptables 检查桥接流量

3.1 安装依赖包

1
yum install -y epel-release conntrack ipvsadm ipset jq sysstat curl iptables libseccomp

3.2 关闭防火墙

1
iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat && iptables -P FORWARD ACCEPT

确保 br_netfilter 模块被加载。这一操作可以通过运行 lsmod | grep br_netfilter 来完成。若要显式加载该模块,可执行 modprobe br_netfilter

为了让你的 Linux 节点上的 iptables 能够正确地查看桥接流量,你需要确保在你的 sysctl 配置中将 net.bridge.bridge-nf-call-iptables 设置为 1。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat <<EOF | tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.ipv6.conf.all.disable_ipv6=1
net.netfilter.nf_conntrack_max=2310720
EOF
sysctl --system

3.3 加载内核模块

1
2
3
4
5
6
7
8
9
10
11
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
modprobe -- br_netfilter
EOF

chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules

4、检查所需端口

4.1 控制平面节点

协议 方向 端口范围 作用 使用者
TCP 入站 6443 Kubernetes API 服务器 所有组件
TCP 入站 2379-2380 etcd 服务器客户端 API kube-apiserver, etcd
TCP 入站 10250 Kubelet API kubelet 自身、控制平面组件
TCP 入站 10251 kube-scheduler kube-scheduler 自身
TCP 入站 10252 kube-controller-manager kube-controller-manager 自身

4.2 工作节点

协议 方向 端口范围 作用 使用者
TCP 入站 10250 Kubelet API kubelet 自身、控制平面组件
TCP 入站 30000-32767 NodePort 服务† 所有组件

5、安装 runtime

为了在 Pod 中运行容器,Kubernetes 使用容器运行时Container Runtime

默认情况下,Kubernetes 使用 容器运行时接口(Container Runtime Interface,CRI) 来与你所选择的容器运行时交互。

如果你不指定运行时,则 kubeadm 会自动尝试检测到系统上已经安装的运行时, 方法是扫描一组众所周知的 Unix 域套接字。 下面的表格列举了一些容器运行时及其对应的套接字路径:

运行时 域套接字
Docker /var/run/dockershim.sock
containerd /run/containerd/containerd.sock
CRI-O /var/run/crio/crio.sock

如果同时检测到 Docker 和 containerd,则优先选择 Docker。 这是必然的,因为 Docker 18.09 附带了 containerd 并且两者都是可以检测到的, 即使你仅安装了 Docker。 如果检测到其他两个或多个运行时,kubeadm 输出错误信息并退出。

kubelet 通过内置的 dockershim CRI 实现与 Docker 集成。

5.1 使用 containerd 作为 CRI 运行时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat <<EOF | tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

modprobe overlay
modprobe br_netfilter

# 设置必需的 sysctl 参数,这些参数在重新启动后仍然存在。
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

# 应用 sysctl 参数而无需重新启动
sysctl --system

5.2 安装 containerd

  1. 从官方Docker仓库安装 containerd.io 软件包

    1
    2
    3
    4
    5
    yum install -y yum-utils
    yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
    yum install -y containerd.io
  2. 配置 containerd

    1
    2
    mkdir -p /etc/containerd
    containerd config default | tee /etc/containerd/config.toml
  3. 重新启动 containerd

    1
    2
    systemctl restart containerd
    systemctl enable containerd

    5.3 使用 systemd cgroup 驱动程序

结合 runc 使用 systemd cgroup 驱动,在 /etc/containerd/config.toml 中设置

1
2
3
4
5
sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2" #换成阿里云
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true

再次重新启动 containerd

1
systemctl restart containerd

6、安装 kubeadm、kubelet 和 kubectl

需要在每台机器上安装以下的软件包:

  • kubeadm:用来初始化集群的指令。
  • kubelet:在集群中的每个节点上用来启动 Pod 和容器等。
  • kubectl:用来与集群通信的命令行工具。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet

kubelet 现在每隔几秒就会重启,因为它陷入了一个等待 kubeadm 指令的死循环。

1
2
3
cat > /etc/sysconfig/kubelet <<EOF
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd --container-runtime=remote --container-runtime-endpoint=/run/containerd/containerd.sock
EOF

7、初始化控制平面节点

如果计划将单个控制平面 kubeadm 集群升级成高可用, 应该指定 --control-plane-endpoint 为所有控制平面节点设置共享端点。 端点可以是负载均衡器的 DNS 名称或 IP 地址。

7.1 kubeadm init

选项

–apiserver-advertise-address string API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认网络接口。
–apiserver-bind-port int32 默认值:6443 API 服务器绑定的端口。
–apiserver-cert-extra-sans stringSlice 用于 API Server 服务证书的可选附加主题备用名称(SAN)。可以是 IP 地址和 DNS 名称。
–cert-dir string 默认值:”/etc/kubernetes/pki” 保存和存储证书的路径
–certificate-key string 用于加密 kubeadm-certs Secret 中的控制平面证书的密钥。
–config string kubeadm 配置文件的路径。
–control-plane-endpoint string 为控制平面指定一个稳定的 IP 地址或 DNS 名称。
–cri-socket string 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。
–dry-run 不要应用任何更改;只是输出将要执行的操作。
–experimental-patches string 包含名为 “target[suffix][+patchtype].extension” 的文件的目录路径。 例如,”kube-apiserver0+merge.yaml” 或仅仅是 “etcd.json”。 “patchtype” 可以是 “strategic”、”merge” 或 “json” 之一,并且它们与 kubectl 支持的补丁格式匹配。 默认的 “patchtype” 为 “strategic”。 “extension” 必须为 “json” 或 “yaml”。 “suffix” 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。
–feature-gates string 一组用来描述各种功能特性的键值(key=value)对。选项是: IPv6DualStack=true|false (ALPHA - default=false)
-h, –help init 操作的帮助命令
–ignore-preflight-errors stringSlice 错误将显示为警告的检查列表;例如:’IsPrivilegedUser,Swap’。取值为 ‘all’ 时将忽略检查中的所有错误。
–image-repository string 默认值:”k8s.gcr.io” 选择用于拉取控制平面镜像的容器仓库
–kubernetes-version string 默认值:”stable-1” 为控制平面选择一个特定的 Kubernetes 版本。
–node-name string 指定节点的名称。
–pod-network-cidr string 指明 pod 网络可以使用的 IP 地址段。如果设置了这个参数,控制平面将会为每一个节点自动分配 CIDRs。
–service-cidr string 默认值:”10.96.0.0/12” 为服务的虚拟 IP 地址另外指定 IP 地址段
–service-dns-domain string 默认值:”cluster.local” 为服务另外指定域名,例如:”myorg.internal”。
–skip-certificate-key-print 不要打印用于加密控制平面证书的密钥。
–skip-phases stringSlice 要跳过的阶段列表
–skip-token-print 跳过打印 ‘kubeadm init’ 生成的默认引导令牌。
–token string 这个令牌用于建立控制平面节点与工作节点间的双向通信。格式为 [a-z0-9]{6}.[a-z0-9]{16} - 示例:abcdef.0123456789abcdef
–token-ttl duration 默认值:24h0m0s 令牌被自动删除之前的持续时间(例如 1 s,2 m,3 h)。如果设置为 ‘0’,则令牌将永不过期
–upload-certs 将控制平面证书上传到 kubeadm-certs Secret。

8、使用自定义的镜像

默认情况下, kubeadm 会从 k8s.gcr.io 仓库拉取镜像。如果请求的 Kubernetes 版本是 CI 标签 (例如 ci/latest),则使用 gcr.io/kubernetes-ci-images

允许的自定义功能有:

  • 使用其他的 imageRepository 来代替 k8s.gcr.io
  • useHyperKubeImage 设置为 true,使用 HyperKube 镜像。
  • 为 etcd 或 DNS 附件提供特定的 imageRepositoryimageTag

请注意配置文件中的配置项 kubernetesVersion 或者命令行参数 --kubernetes-version 会影响到镜像的版本。

以使用 kubeadm config print 命令打印默认配置, 并使用 kubeadm config migrate 命令将旧版本的配置转化成新版本。 kubeadm config images listkubeadm config images pull 命令可以用来列出并拉取 kubeadm 所需的镜像。

8.1 拉取阿里云镜像

1
kubeadm config images pull --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers

8.2 初始化

1
kubeadm init   --kubernetes-version=v1.21.0   --pod-network-cidr=10.244.0.0/16   --apiserver-advertise-address=192.168.120.128   --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers

备注:如果初始化有问题,使用reset重置

image-20210507164407170

1
2
3
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

8.3 安装calico网络

1
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml#移除母版上的污点kubectl taint nodes --all node-role.kubernetes.io/master-

8.4 添加自动补全命令

1
2
3
4
yum install -y epel-release bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

根据初始化成功的提示加入从节点即可

1、介绍

​ 此命令的设计者有 3 位,他们的姓分别是 Aho、Weingberger 和 Kernighan,awk 就取自这 3 为大师姓的首字母。和 sed 命令类似,awk 命令也是逐行扫描文件(从第 1 行到最后一行),寻找含有目标文本的行,如果匹配成功,则会在该行上执行用户想要的操作;反之,则不对行做任何处理。

2、基本语法

awk 命令的基本格式为:

1
[root@localhost ~]# awk [选项] '脚本命令' 文件名

此命令常用的选项以及各自的含义,如表

选项 含义
-F fs 指定以 fs 作为输入行的分隔符,awk 命令默认分隔符为空格或制表符。
-f file 从脚本文件中读取 awk 脚本指令,以取代直接在命令行中输入指令。
-v var=val 在执行处理过程之前,设置一个变量 var,并给其设备初始值为 val。

awk 的强大之处在于脚本命令,它由 2 部分组成,分别为匹配规则和执行命令,如下所示:

1
'匹配规则{执行命令}'

​ 这里的匹配规则,和 sed 命令中的 address 部分作用相同,用来指定脚本命令可以作用到文本内容中的具体行,可以使用字符串(比如 /demo/,表示查看含有 demo 字符串的行)或者正则表达式指定。另外需要注意的是,整个脚本命令是用单引号(’’)括起,而其中的执行命令部分需要用大括号({})括起来。

在 awk 程序执行时,如果没有指定执行命令,则默认会把匹配的行输出;如果不指定匹配规则,则默认匹配文本中所有的行。

举个简单的例子:

1
[root@localhost ~]# awk '/^$/ {print "Blank line"}' test.txt

​ 在此命令中,/^$/ 是一个正则表达式,功能是匹配文本中的空白行,同时可以看到,执行命令使用的是 print 命令,此命令经常会使用,它的作用很简单,就是将指定的文本进行输出。因此,整个命令的功能是,如果 test.txt 有 N 个空白行,那么执行此命令会输出 N 个 Blank line。

3、awk 使用数据字段变量

awk 的主要特性之一是其处理文本文件中数据的能力,它会自动给一行中的每个数据元素分配一个变量。

默认情况下,awk 会将如下变量分配给它在文本行中发现的数据字段:

  • $0 代表整个文本行;
  • $1 代表文本行中的第 1 个数据字段;
  • $2 代表文本行中的第 2 个数据字段;
  • $n 代表文本行中的第 n 个数据字段。

前面说过,在 awk 中,默认的字段分隔符是任意的空白字符(例如空格或制表符)。 在文本行中,每个数据字段都是通过字段分隔符划分的。awk 在读取一行文本时,会用预定义的字段分隔符划分每个数据字段。

所以在下面的例子中,awk 程序读取文本文件,只显示第 1 个数据字段的值:

1
2
3
4
5
6
7
8
9
10
[root@node1 ~]# cat data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
[root@node1 ~]# awk '{print $5}' data2.txt
1.
2.
3.
4.

该程序用 $5 字段变量来表示“仅显示每行文本的第 5 个数据字段”。当然,如果你要读取采用了其他字段分隔符的文件,可以用 -F 选项手动指定。

4、awk 脚本命令使用多个命令

awk 允许将多条命令组合成一个正常的程序。要在命令行上的程序脚本中使用多条命令,只要在命令之间放个分号即可,例如:

1
2
3
4
5
6
7
8
9
10
[root@node1 ~]# cat data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
[root@node1 ~]# awk '{$4="line";print $0}' data2.txt
This is line line 1.
This is line line 2.
This is line line 3.
This is line line 4.

第一条命令会给字段变量 $4 赋值。第二条命令会打印整个数据字段。可以看到,awk 程序在输出中已经将原文本中的第四个数据字段替换成了新值。

除此之外,也可以一次一行地输入程序脚本命令,比如说:

1
2
3
4
5
[root@node1 ~]# awk '{
> $3="tom"
> print $0}'
my name hello
my name tom

在你用了表示起始的单引号后,bash shell 会使用 > 来提示输入更多数据,我们可以每次在每行加一条命令,直到输入了结尾的单引号。

注意,此例中因为没有在命令行中指定文件名,awk 程序需要用户输入获得数据,因此当运行这个程序的时候,它会一直等着用户输入文本,此时如果要退出程序,只需按下 Ctrl+D 组合键即可。

5、awk从文件中读取程序

跟 sed 一样,awk 允许将脚本命令存储到文件中,然后再在命令行中引用,比如:

1
2
3
4
5
6
7
8
[root@node1 ~]# cat awk.sh
#!/bin/bash
{print $1 "'s wellcom to beijing'" $6}
[root@node1 ~]# awk -F: -f awk.sh /etc/passwd
root's wellcom to beijing'/root
bin's wellcom to beijing'/bin
daemon's wellcom to beijing'/sbin
adm's wellcom to beijing'/var/adm

awk.sh 脚本文件会使用 print 命令打印 /etc/passwd 文件的主目录数据字段(字段变量 $6),以及 userid 数据字段(字段变量 $1)。注意,在程序文件中,也可以指定多条命令,只要一条命令放一行即可,之间不需要用分号。

6、awk BEGIN关键字

awk 中还可以指定脚本命令的运行时机。默认情况下,awk 会从输入中读取一行文本,然后针对该行的数据执行程序脚本,但有时可能需要在处理数据前运行一些脚本命令,这就需要使用 BEGIN 关键字。

BEGIN 会强制 awk 在读取数据前执行该关键字后指定的脚本命令,例如:

1
2
3
4
5
6
7
8
9
10
11
[root@node1 ~]# cat data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
[root@node1 ~]# awk 'BEGIN {print "hello world:"} {print $5}' data2.txt
hello world:
1.
2.
3.
4.

可以看到,这里的脚本命令中分为 2 部分,BEGIN 部分的脚本指令会在 awk 命令处理数据前运行,而真正用来处理数据的是第二段脚本命令。

7、awk END关键字

和 BEGIN 关键字相对应,END 关键字允许我们指定一些脚本命令,awk 会在读完数据后执行它们,例如:

1
2
3
4
5
6
7
[root@node1 ~]# awk 'BEGIN {print "hello world:"} {print $5} END {print "love china"}' data2.txt
hello world:
1.
2.
3.
4.
love china

可以看到,当 awk 程序打印完文件内容后,才会执行 END 中的脚本命令。

8、归纳总结

(一)内置变量

\1. 每一行内容记录,叫做记录,英文名称 Record

\2. 每行中通过分隔符隔开的每一列,叫做字段,英文名称 Field

明确这几个概念后,我们来总结几个重要的内置变量:

  • NR:表示当前的行数;
  • NF:表示当前的列数;
  • RS:行分隔符,默认是换行;
  • FS:列分隔符,默认是空格和制表符;
  • OFS:输出列分隔符,用于打印时分割字段,默认为空格
  • ORS:输出行分隔符,用于打印时分割记录,默认为换行符

(二)输出格式

awk 提供 printf 函数进行格式化输出功能,具体的使用方式和 C 语法基本一致。

基本用法

1
printf("%12s, %02d, %0.2f\n", s, d, g);

常用的格式化方式:

  • %d 十进制有符号整数
  • %u 十进制无符号整数
  • %f 浮点数
  • %s 字符串
  • %c 单个字符
  • %e 指数形式的浮点数
  • %x %X 无符号以十六进制表示的整数
  • %0 无符号以八进制表示的整数
  • %g 自动选择合适的表示法
  • \n 换行符
  • \t Tab符

(三)编程语句

awk 不仅是一个 Linux 命令行工具,它其实是一门脚本语言,支持程序设计语言所有的控制结构,它支持:

  • 条件语句
  • 循环语句
  • 数组
  • 函数

(四)常用函数

awk 内置了大量的有用函数功能,也支持自定义函数,允许你编写自己的函数来扩展内置函数。

这里只简单罗列一些比较常用的字符串函数:

  • index(s, t) 返回子串 t 在 s 中的位置
  • length(s) 返回字符串 s 的长度
  • split(s, a, sep) 分割字符串,并将分割后的各字段存放在数组 a 中
  • substr(s, p, n) 根据参数,返回子串
  • tolower(s) 将字符串转换为小写
  • toupper(s) 将字符串转换为大写

grep 命令的由来可以追溯到 UNIX 诞生的早期,在 UNIX 系统中,搜索的模式(patterns)被称为正则表达式(regular expressions),为了要彻底搜索一个文件,有的用户在要搜索的字符串前加上前缀 global(全面的),一旦找到相匹配的内容,用户就像将其输出(print)到屏幕上,而将这一系列的操作整合到一起就是 global regular expressions print,而这也就是 grep 命令的全称。

grep命令能够在一个或多个文件中,搜索某一特定的字符模式(也就是正则表达式),此模式可以是单一的字符、字符串、单词或句子。

正则表达式是描述一组字符串的一个模式,正则表达式的构成模仿了数学表达式,通过使用操作符将较小的表达式组合成一个新的表达式。正则表达式可以是一些纯文本文字,也可以是用来产生模式的一些特殊字符。为了进一步定义一个搜索模式,grep 命令支持如下表所示的这几种正则表达式的元字符(也就是通配符)。

通配符 功能
c* 将匹配 0 个(即空白)或多个字符 c(c 为任一字符)。
. 将匹配任何一个字符,且只能是一个字符。
[xyz] 匹配方括号中的任意一个字符。
[^xyz] 匹配除方括号中字符外的所有字符。
^ 锁定行的开头。
$ 锁定行的结尾。

需要注意的是,在基本正则表达式中,如通配符 、+、{、|、( 和 )等,已经失去了它们原本的含义,而若要恢复它们原本的含义,则要在之前添加反斜杠 \,如 \、+、{、|、( 和 )。

grep 命令是用来在每一个文件或中(或特定输出上)搜索特定的模式,当使用 grep 时,包含指定字符模式的每一行内容,都会被打印(显示)到屏幕上,但是使用 grep 命令并不改变文件中的内容。

这里的模式,要么是字符(串),要么是正则表达式。而此命令常用的选项以及各自的含义如下表所示。

选项 含义
-c 仅列出文件中包含模式的行数。
-i 忽略模式中的字母大小写。
-l 列出带有匹配行的文件名。
-n 在每一行的最前面列出行号。
-v 列出没有匹配模式的行。
-w 把表达式当做一个完整的单字符来搜寻,忽略那些部分匹配的行。

注意,如果是搜索多个文件,grep 命令的搜索结果只显示文件中发现匹配模式的文件名;而如果搜索单个文件,grep 命令的结果将显示每一个包含匹配模式的行。

1、介绍

sed 会根据脚本命令来处理文本文件中的数据,这些命令要么从命令行中输入,要么存储在一个文本文件中,此命令执行数据的顺序如下:

  1. 每次仅读取一行内容;
  2. 根据提供的规则命令匹配并修改数据。注意,sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区中的数据;
  3. 将执行结果输出。

当一行数据匹配完成后,它会继续读取下一行数据,并重复这个过程,直到将文件中所有数据处理完毕。

2、格式

sed 命令的基本格式如下:

1
[root@localhost ~]# sed [选项] [脚本命令] 文件名

该命令常用的选项及含义,如表图所示

选项 含义
-e 脚本命令 该选项会将其后跟的脚本命令添加到已有的命令中。
-f 脚本命令文件 该选项会将其后文件中的脚本命令添加到已有的命令中。
-n 默认情况下,sed 会在所有的脚本指定执行完毕后,会自动输出处理后的内容,而该选项会屏蔽启动输出,需使用 print 命令来完成输出。
-i 此选项会直接修改源文件,要慎用。

3、参数

文件:指定待处理的文本文件列表。

sed常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
a\ 在当前行下面插入文本;
i\ 在当前行上面插入文本;
c\ 把选定的行改为新的文本;
d 删除,删除选择的行;
D 删除模板块的第一行;
s 替换指定字符;
h 拷贝模板块的内容到内存中的缓冲区;
H 追加模板块的内容到内存中的缓冲区;
g 获得内存缓冲区的内容,并替代当前模板块中的文本;
G 获得内存缓冲区的内容,并追加到当前模板块文本的后面;
l 列表不能打印字符的清单;
n 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令;
N 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码;
p 打印模板块的行。 P(大写) 打印模板块的第一行;
q 退出Sed;
b lable 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾;
r file 从file中读行;
t label if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾;
T label 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾;
w file 写并追加模板块到file末尾;
W file 写并追加模板块的第一行到file末尾;
! 表示后面的命令对所有没有被选定的行发生作用;
= 打印当前行号;
# 把注释扩展到下一个换行符以前;

sed替换标记

1
2
3
4
5
6
7
g 表示行内全面替换;
p 表示打印行;
w 表示把行写入一个文件;
x 表示互换模板块中的文本和缓冲区中的文本;
y 表示把一个字符翻译为另外的字符(但是不用于正则表达式);
\1 子串匹配标记;
& 已匹配字符串标记;

sed元字符集

1
2
3
4
5
6
7
8
9
10
11
12
13
^ 匹配行开始,如:/^sed/匹配所有以sed开头的行;
$ 匹配行结束,如:/sed$/匹配所有以sed结尾的行;
. 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d;
* 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行;
[] 匹配一个指定范围内的字符,如/[ss]ed/匹配sed和Sed;
[^] 匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行;
\(..\) 匹配子串,保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers;
& 保存搜索字符用来替换其他字符,如s/love/**&**/,love这成**love**;
\< 匹配单词的开始,如:/\
\> 匹配单词的结束,如/love\>/匹配包含以love结尾的单词的行;
x\{m\} 重复字符x,m次,如:/0\{5\}/匹配包含5个0的行;
x\{m,\} 重复字符x,至少m次,如:/0\{5,\}/匹配至少有5个0的行;
x\{m,n\} 重复字符x,至少m次,不多于n次,如:/0\{5,10\}/匹配5~10个0的行;

4、脚本命令

4.1 替换命令:s

此命令的基本格式为:

1
[address]s/pattern/replacement/flags

其中,address 表示指定要操作的具体行,pattern 指的是需要替换的内容,replacement 指的是要替换的新内容。

此命令中常用的 flags 标记如下表所示

flags 标记 功能
n 1~512 之间的数字,表示指定要替换的字符串出现第几次时才进行替换,例如,一行中有 3 个 A,但用户只想替换第二个 A,这是就用到这个标记;
g 对数据中所有匹配到的内容进行替换,如果没有 g,则只会在第一次匹配成功时做替换操作。例如,一行数据中有 3 个 A,则只会替换第一个 A;
p 会打印与替换命令中指定的模式匹配的行。此标记通常与 -n 选项一起使用。
w file 将缓冲区中的内容写到指定的 file 文件中;
& 用正则表达式匹配的内容进行替换;
\n 匹配第 n 个子串,该子串之前在 pattern 中用 () 指定。
\ 转义(转义替换部分包含:&、\ 等)。

查看原文件

1
2
3
[root@node1 ~]# cat data1.txt
This is a test of the test script.
This is the second test of the test script.

替换后为

1
2
3
[root@node1 ~]# sed 's/test/hello/2' data1.txt
This is a test of the hello script.
This is the second test of the hello script.

可以看到,使用数字 2 作为标记的结果就是,sed 编辑器只替换每行中第 2 次出现的匹配模式。

如果要用新文件替换所有匹配的字符串,可以使用 g 标记:

1
2
3
[root@node1 ~]# sed 's/test/hello/g' data1.txt
This is a hello of the hello script.
This is the second hello of the hello script.

-n 选项会禁止 sed 输出,但 p 标记会输出修改过的行,将二者匹配使用的效果就是只输出被替换命令修改过的行,例如:

1
2
3
4
5
[root@node1 ~]# cat data1.txt
This is a test of the test script.
This is the second test of the test script.
[root@node1 ~]# sed -n 's/second/hello/p' data1.txt
This is the hello test of the test script.

w 标记会将匹配后的结果保存到指定文件中,比如:

1
2
3
4
5
[root@node1 ~]# sed 's/second/hello/w test.txt' data1.txt
This is a test of the test script.
This is the hello test of the test script.
[root@node1 ~]# cat test.txt
This is the hello test of the test script.

在使用 s 脚本命令时,替换类似文件路径的字符串会比较麻烦,需要将路径中的正斜线进行转义,例如:

1
2
3
4
[root@node1 ~]# cat /etc/passwd
test:x:1000:1000::/home/test:/bin/bash
[root@node1 ~]# sed -n 's/\/home\/test/\/home\/hello/p' /etc/passwd
test:x:1000:1000::/home/hello:/bin/bash

以上命令中字符 / 在sed中作为定界符使用,也可以使用任意的定界符

1
2
3
4
5
6
7
8
9
[root@node1 ~]# sed 's:test:ok:g' data1.txt
This is a ok of the ok script.
This is the second ok of the ok script.
[root@node1 ~]# sed 's#test#ok1#g' data1.txt
This is a ok1 of the ok1 script.
This is the second ok1 of the ok1 script.
[root@node1 ~]# sed 's|test|ok2|g' data1.txt
This is a ok2 of the ok2 script.
This is the second ok2 of the ok2 script.

4.2 删除命令:d

删除空白行

1
2
3
4
5
6
7
8
9
10
[root@node1 ~]# cat data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
[root@node1 ~]# sed '/^$/d' data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.

删除指定行

1
2
3
4
[root@node1 ~]# sed '2d' data2.txt
This is line number 1.
This is line number 3.
This is line number 4.

删除第二行到末尾所有行

1
2
[root@node1 ~]# sed '2,$d' data2.txt
This is line number 1.

删除最后一行

1
2
3
4
[root@node1 ~]# sed '$d' data2.txt
This is line number 1.
This is line number 2.
This is line number 3.

在此强调,在默认情况下 sed 并不会修改原始文件,这里被删除的行只是从 sed 的输出中消失了,原始文件没做任何改变。

4.3 插入命令:a和i

a 命令表示在指定行的后面附加一行,i 命令表示在指定行的前面插入一行,这里之所以要同时介绍这 2 个脚本命令,因为它们的基本格式完全相同,如下所示:

1
2
3
4
5
6
[root@node1 ~]# sed '3i/This is an inserted line.' data2.txt
This is line number 1.
This is line number 2.
This is an inserted line.
This is line number 3.
This is line number 4.
1
2
3
4
5
6
[root@node1 ~]# sed '3a/This is an inserted line.' data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an inserted line.
This is line number 4.

4.4 替换文本命令:c

c 命令表示将指定行中的所有内容,替换成该选项后面的字符串。

1
2
3
4
5
[root@node1 ~]# sed '3c/This is an inserted line test.' data2.txt
This is line number 1.
This is line number 2.
This is an inserted line test.
This is line number 4.

4.5 转换命令:y

y 转换命令是唯一可以处理单个字符的 sed 脚本命令

转换命令会对 inchars 和 outchars 值进行一对一的映射,即 inchars 中的第一个字符会被转换为 outchars 中的第一个字符,第二个字符会被转换成 outchars 中的第二个字符…这个映射过程会一直持续到处理完指定字符。如果 inchars 和 outchars 的长度不同,则 sed 会产生一条错误消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@node1 ~]# cat data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is line number 5.
This is line number 6.
This is line number 7.
This is line number 8.
This is line number 9.
[root@node1 ~]# sed 'y/123/789/' data2.txt
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4.
This is line number 5.
This is line number 6.
This is line number 7.
This is line number 8.
This is line number 9.

可以看到,inchars 模式中指定字符的每个实例都会被替换成 outchars 模式中相同位置的那个字符。

转换命令是一个全局命令,也就是说,它会文本行中找到的所有指定字符自动进行转换,而不会考虑它们出现的位置,再打个比方:

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
[root@node1 ~]# cat data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is line number 5.
This is line number 6.
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 10.
This is line number 11.
This is line number 12.
[root@node1 ~]# sed 'y/123/789/' data2.txt
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4.
This is line number 5.
This is line number 6.
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 70.
This is line number 77.
This is line number 78.

sed 转换了在文本行中匹配到的字符,无法限定只转换在特定地方出现的字符。

4.6 打印命令:p

p 命令表示搜索符号条件的行,并输出该行的内容

1
2
3
4
5
6
7
[root@node1 ~]# cat data2.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
[root@node1 ~]# sed -n '/number 2/p' data2.txt
This is line number 2.

可以看到,用 -n 选项和 p 命令配合使用,我们可以禁止输出其他行,只打印包含匹配文本模式的行。

如果需要在修改之前查看行,也可以使用打印命令,比如与替换或修改命令一起使用。可以创建一个脚本在修改行之前显示该行,如下所示:

1
2
3
[root@node1 ~]# sed -n '/3/{> p> s/line/test/p> }' data2.txt
This is line number 3.
This is test number 3.

4.7 写入命令:w

w 命令用来将文本中指定行的内容写入文件中,如果不想让行直接输出,可以用 -n 选项

可以看到,通过使用 w 脚本命令,sed 可以实现将包含文本模式的数据行写入目标文件。

1
2
3
4
[root@node1 ~]# sed -n '1,2w test2.txt' data2.txt
[root@node1 ~]# cat test2.txt
This is line number 1.
This is line number 2.

4.8 插入文件命令:r

r 命令用于将一个独立文件的数据插入到当前数据流的指定位置

1
2
3
4
5
6
7
8
9
10
[root@node1 ~]# cat test2.txt
hello world
This is line number 2.
[root@node1 ~]# sed '2r test2.txt' data2.txt
This is line number 1.
This is line number 2.
hello world
This is line number 2.
This is line number 3.
This is line number 4.

如果你想将指定文件中的数据插入到数据流的末尾,可以使用 $ 地址符

4.9 退出命令:q

q 命令的作用是使 sed 命令在第一次匹配任务结束后,退出 sed 程序,不再进行对后续数据的处理。

1
2
3
[root@node1 ~]# sed '2q' data2.txt
This is line number 1.
This is line number 2.

4.10 多点编辑:e

允许在同一行里执行多条命令:

1
2
3
4
[root@node1 ~]# sed -e '1d' -e 's/line/hello/' data2.txt
This is hello number 2.
This is hello number 3.
This is hello number 4.

1、介绍

​ 从字面意思上,rsync 可以理解为 remote sync(远程同步),但它不仅可以远程同步数据(类似于 scp 命令),还可以本地同步数据(类似于 cp 命令)。不同于 cp 或 scp 的一点是,使用 rsync 命令备份数据时,不会直接覆盖以前的数据(如果数据已经存在),而是先判断已经存在的数据和新数据的差异,只有数据不同时才会把不相同的部分覆盖。

2、安装

在Centos中使用以下命令安装rsync:

1
yum install -y rsync

3、工作模式

rsync 有 5 种不同的工作模式:

  • 第一种用于仅在本地备份数据;
  • 第二种用于将本地数据备份到远程机器上;
  • 第三种用于将远程机器上的数据备份到本地机器上;
  • 第四种和第三种是相对的,同样第五种和第二种是相对的,它们各自之间的区别在于登陆认证时使用的验证方式不同。

要知道,使用 rsync 在远程传输数据(备份数据)前,是需要进行登陆认证的,这个过程需要借助 ssh 协议或者 rsync 协议才能完成。在 rsync 命令中,如果使用单个冒号(:),则默认使用 ssh 协议;反之,如果使用两个冒号(::),则使用 rsync 协议。

ssh 协议和 rsync 协议的区别在于,rsync 协议在使用时需要额外配置,增加了工作量,但优势是更加安全;反之,ssh 协议使用方便,无需进行配置,但有泄漏服务器密码的风险。

4、参数列表

另外,以上几种格式中各个参数的含义如下:

  • SRC:用来表示要备份的目标数据所在的位置(路径);
  • DEST:用于表示将数据备份到什么位置;
  • USER@:当做远程同步操作时,需指明系统登录的用户名,如果不显示指定,默认为以 root 身份登录系统并完成同步操作。

rsync 命令提供使用的 OPTION 及功能如表

OPTION选项 功能
-a 这是归档模式,表示以递归方式传输文件,并保持所有属性,它等同于-r、-l、-p、-t、-g、-o、-D 选项。-a 选项后面可以跟一个 –no-OPTION,表示关闭 -r、-l、-p、-t、-g、-o、-D 中的某一个,比如-a –no-l 等同于 -r、-p、-t、-g、-o、-D 选项。
-r 表示以递归模式处理子目录,它主要是针对目录来说的,如果单独传一个文件不需要加 -r 选项,但是传输目录时必须加。
-v 表示打印一些信息,比如文件列表、文件数量等。
-l 表示保留软连接。
-L 表示像对待常规文件一样处理软连接。如果是 SRC 中有软连接文件,则加上该选项后,将会把软连接指向的目标文件复制到 DEST。
-p 表示保持文件权限。
-o 表示保持文件属主信息。
-g 表示保持文件属组信息。
-D 表示保持设备文件信息。
-t 表示保持文件时间信息。
–delete 表示删除 DEST 中 SRC 没有的文件。
–exclude=PATTERN 表示指定排除不需要传输的文件,等号后面跟文件名,可以是通配符模式(如 *.txt)。
–progress 表示在同步的过程中可以看到同步的过程状态,比如统计要同步的文件数量、 同步的文件传输速度等。
-u 表示把 DEST 中比 SRC 还新的文件排除掉,不会覆盖。
-z 加上该选项,将会在传输过程中压缩。

5、本机中的两个目录进行同步

要同步本地计算机中的两个目录,使用rsync -zvr命令:

1
2
3
4
5
6
7
8
9
[root@node1 ~]# mkdir /rsync
[root@node1 ~]# rsync -zvr /var/log/ /rsync/
sending incremental file list
boot.log
......
tuned/tuned.log

sent 465,270 bytes received 759 bytes 932,058.00 bytes/sec
total size is 4,754,906 speedup is 10.20

6、使用rsync -a选项

rsync命令的-a选项表示存档模式。-a选项递归同步,保留符号链接,保留权限,保留,保留所有者和组。

现在,执行以下命令,然后查看文件的时间:

1
2
3
4
5
6
7
8
9
[root@node1 ~]# rsync -zva /var/log/ /rsync/
sending incremental file list
./
boot.log
......
tuned/tuned.log

sent 465,714 bytes received 762 bytes 932,952.00 bytes/sec
total size is 4,759,531 speedup is 10.20

如下图所示,在同步期间保留了补充

image-20210429152235649

image-20210429152252882

7、将文件从本地同步到远程目录

rsync允许在本地和远程系统之间的同步文件/目录,应该是本地和远程系统都要安装rsync才行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@node1 ~]# rsync -zva /var/log/ root@192.168.10.200:/rsync
The authenticity of host '192.168.10.200 (192.168.10.200)' can't be established.
ECDSA key fingerprint is SHA256:CQ+Ueun/hBJkSNzWjqdNDLc3bFsfS8RwWTYeX3aD3Ak.
ECDSA key fingerprint is MD5:4d:fd:8a:6f:99:16:33:39:fb:c9:7c:1b:16:61:ea:07.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.200' (ECDSA) to the list of known hosts.
root@192.168.10.200's password:
sending incremental file list
created directory /rsync
./
boot.log
......
tuned/tuned.log

sent 465,718 bytes received 791 bytes 71,770.62 bytes/sec
total size is 4,759,531 speedup is 10.20

8、将文件从远程目录同步到本地

将目标文件从远程系统同步到本地时,在源中指定远程路径,在目标中指定本地路径即可:

1
2
3
4
5
6
7
8
9
10
[root@node1 ~]# rsync -avz root@192.168.10.200:/rsync/ /test1/
root@192.168.10.200's password:
receiving incremental file list
./
boot.log
......
tuned/tuned.log

sent 770 bytes received 465,673 bytes 103,654.00 bytes/sec
total size is 4,759,531 speedup is 10.20

9、不传输大文件

可以使用rsync --max-size选项告诉rsync不要传输大于指定大小的文件。

1
2
3
4
5
6
7
8
9
10
11
[root@node1 ~]# rsync -zva --max-size='1M' /var/log/ root@192.168.10.200:/rsync1
root@192.168.10.200's password:
sending incremental file list
created directory /rsync1
./
boot.log
......
tuned/tuned.log

sent 279,991 bytes received 773 bytes 112,305.60 bytes/sec
total size is 4,773,150 speedup is 17.00

image-20210429154749416

--max-size=1M使rsync仅传输小于或等于1M的文件。单位可以是K,M,G等。

还可以使用--min-size=参数,指定传输最小文件的大小。

1、Shell变量介绍

​ Linux中的变量分为系统变量和自定义变量

2、Shell变量的定义

基本语法

  1. 定义变量:变量=值
  2. 撤销变量:unset 变量
  3. 声明静态变量:readonly变量(不能unset)readonly city=beijing

定义变量的规则

  1. 变量名称可以由字母、数字和下划线组成,但不能使用数字开头
  2. 变量两侧不能有空格
  3. 变量名称一般习惯为大写

将命令的返回值赋给变量

  • A=date 两个反引号`将命令引起来,并将结果返回给变量A
  • A=$(date) 等价于反引号

3、设置环境变量

基本语法

  • export 变量名=变量值
  • source 配置文件
  • echo $变量名

4、位置参数变量

基本语法

  • $n 功能描述:n为数字,$0表示命令本身,$1–$9代表第一个到第九个参数,十以上的参数需要用大括号包含(${10})
  • $* 功能描述:代表命令行中所有的参数,把所有的参数看做一个整体
  • $@ 功能描述:代表命令行中所有的参数,不过把每个参数区分对待
  • $# 功能描述:代表命令行中所有参数的个数
1
2
3
4
5
#!/bin/bash
echo "0=$0 1=$1 2=$2"
echo "所有的参数为$*"
echo "所有的参数为$@"
echo "所有的参数为$#"

输出结果如下:

1
2
3
4
5
[root@node1 shell]# bash myshell.sh 12 34
0=myshell.sh 1=12 2=34
所有的参数为12 34
所有的参数为12 34
所有的参数为2

5、预定义变量

基本介绍

​ 就是shell设计者事先已经定义好的变量,可以直接在shell脚本使用

基本语法

  • $$ 功能描述:当前进程的进程号(PID)
  • $! 功能描述:后台运行的最后一个进程的进程号(PID)
  • $? 功能描述:最后一次执行命令的返回状态,如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己决定),则证明上一个命令执行不正确。

6、运算符

基本语法

  1. “$((运算式))”或$[运算式]或者expr m + n
  2. 注意expr运算符间要有空格
  3. expr *,/,% 乘,除,取余
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
RES1=$((2+3))
echo "$RES1"

RES2=$[(2+3)*4]
echo "$RES2"

RES3=`expr 2 + 3`
RES4=`expr $RES3 \* 4`
echo "$RES3 $RES4"

结果如下

1
2
3
4
[root@node1 shell]# bash myshell.sh
5
20
5 20

7、条件判断

1、条件判断语法结构

    1. test 条件表达式
    2. [ 条件表达式 ]
    3. [[[ 条件表达式 ]] 支持正则 =~条件判断相关参数

2、条件判断相关参数

2.1 判断文件类型

判断参数 含义
-e 判断文件是否存在(任意文件类型)
-f 判断文件是否存在,并且是一个普通文件
-d 判断文件是否存在,并且是一个目录
-L 判断文件是否存在并且是一个软连接文件
-b 判断文件是否存在并且是一块设备文件
-c 判断文件是否存在是一个字符设备文件
-S 判断文件是否存在并且是一个套接字文件
-p 判断文件是否存在并且是一个命名管道文件
-s 判断文件是否存在并且是否非空文件

2.2 判断文件权限

判断参数 含义
-r 当前用户对其是否可读
-w 当前用户对其是否可写
-x 当前用户对其是否可执行
-u 是否有suid,高级权限冒险家位
-g 是否sgid,高级权限限制位
-k 是否有t位,高级权限粘滞位

2.3 判断文件新旧

判断参数 含义
file1 -nt file2 比较file1是否比file2新
file1 -ot file2 比较file1 是否比file2旧
file1 -ef file2 比较是否为同一个文件,或者判断硬连接,是否指向同一个inode

2.4 判断整数

判断参数 含义
-eq 相等
-ne 不等
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于

2.5 判断字符串

判断参数 含义
-z 判断是否为空字符串,字符串长度为0则成立
-n 判断是否为空字符串,字符串长度不为0则成立
string1 = string2 判断字符串是否相等
string1 != string2 判断字符串是否不相等

2.6 多重条件判断

判断符号 含义
-a 和 && 逻辑与
-o 和 || 逻辑或

特别说明:

  • && 前面表达式为真,才会执行后面代码
  • || 前面表达式为假,才会执行后面代码
  • ; 用于分割命令或表达式

8、流程控制

8.1 case语句

基本语法

1
2
3
4
5
6
7
8
9
10
11
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
*)
echo "我也不知道周几了"
;;
esac

输出结果:

1
2
3
4
[root@node1 shell]# bash myshell.sh 3
我也不知道周几了
[root@node1 shell]# bash myshell.sh 2
周二

8.2 for循环

语法一

1
2
3
4
for  变量  in  值1  值2  值3
do
程序代码
done
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
for i in "$*"
do
echo "num is $i"
done
echo "================"
for j in "$@"
do
echo "num is $j"
done

输出结果:

1
2
3
4
5
6
[root@node1 shell]# bash myshell.sh 1 22 44
num is 1 22 44
================
num is 1
num is 22
num is 44

语法二

1
2
3
4
for ((初始值;循环控制条件;变量变化))
do
程序代码
done
1
2
3
4
5
6
#!/bin/bash
SUM=0
for (( i=1;i<=$1;i++ )) #两侧括号有空格do
SUM=$[$SUM+$i]
done
echo "SUM=$SUM"

输出结果:

1
2
[root@node1 shell]# bash myshell.sh 100
SUM=5050

8.3 while循环

基本语法

1
2
3
4
while [ 条件判断式 ]   #注意空格
do
程序代码
done
1
2
3
4
5
6
7
8
9
#!/bin/bash
SUM=0
i=0
while [ $i -le $1 ]
do
i=$[$i+1]
SUM=$[$SUM+$i]
done
echo "结果SUM=$SUM"

输出结果:

1
2
[root@node1 shell]# bash myshell.sh 100
结果SUM=5151

8.4 read读取控制台输入

基本语法

1
2
3
4
5
6
7
8
9
10
read (选项) (参数)选项:
-a:将分裂后的字段依次存储到指定的数组中,存储的起始位置从数组的index=0开始。
-d:指定读取行的结束符号。默认结束符号为换行符。
-n:限制读取N个字符就自动结束读取,如果没有读满N个字符就按下回车或遇到换行符,则也会结束读取。
-N:严格要求读满N个字符才自动结束读取,即使中途按下了回车或遇到了换行符也不结束。其中换行符或回车算一个字符。
-p:给出提示符。默认不支持"\n"换行,要换行需要特殊处理,通过$'string'的方式特殊处理,就可以实现换行的功能
-r:禁止反斜线的转义功能。这意味着"\"会变成文本的一部分。
-s:静默模式。输入的内容不会回显在屏幕上。
-t:给出超时时间,在达到超时时间时,read退出并返回错误。也就是说不会读取任何内容,即使已经输入了一部分。
-u:从给定文件描述符(fd=N)中读取数据
1
2
3
#!/bin/bash
read -s -p $'请输入密码:\n' PASSWORD #使用了换行
echo "密码为$PASSWORD"

输出结果:

1
2
3
[root@node1 shell]# bash myshell.sh
请输入密码:
密码为12345

有的时候pod里面调域名,需要写到 /etc/hosts 里面进行域名解析,但很不幸,/etc/hosts 被 k8s 征用了,无法修改。

但 k8s 给我们提供了 hostAliases 来解决此问题。

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
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
hostAliases:
- ip: "192.168.0.11"
hostnames:
- "www.yangpiqiulaotou.cn"
- "yangpiqiulaotou.cn"
containers:
- image: nginx:alpine
name: nginx
ports:
- containerPort: 80
protocol: TCP

进入pod查看hosts已经生效!