二进制搭建k8s

实验环境:

k8s集群master01:192.168.1.11

k8s集群master02:192.168.1.22

master虚拟ip:192.168.1.100

k8s集群node01:192.168.1.33

k8s集群node01:192.168.1.44

nginx+keepalive01(master):192.168.1.55

nginx+keepalive02(backup):192.168.1.66

在所有机器上初始化系统:

systemctl stop firewalld
systemctl disable firewalld
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X

#关闭selinux
setenforce 0
sed -i 's/enforcing/disabled/' /etc/selinux/config

#关闭swap
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab 

#分别设置主机名
hostnamectl set-hostname master01
hostnamectl set-hostname master02
hostnamectl set-hostname node01
hostnamectl set-hostname node02

#添加hosts文件
cat >> /etc/hosts << EOF
192.168.1.11 master01
192.168.1.22 master02
192.168.1.33 node01
192.168.1.44 node02
EOF

#调整内核参数
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv6.conf.all.disable_ipv6=1
net.ipv4.ip_forward=1
EOF
#开启网桥模式,可将网桥的流量传递给iptables链
#关闭ipv6协议
sysctl --system

#时间同步
yum install ntpdate -y
ntpdate time.windows.com

在所有node节点部署docker:

yum install -y yum-utils device-mapper-persistent-data lvm2 
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 
yum install -y docker-ce docker-ce-cli containerd.io
systemctl start docker.service
systemctl enable docker.service 

部署etcd集群:

准备cfssl证书生成工具cfssl、cfssljson、cfssl-certinfo放在master01上的/usr/local/bin/下并赋予执行权限

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssljson
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O /usr/local/bin/cfssl-certinfo
chmod +x /usr/local/bin/cfssl*

创建/opt/k8s/目录并使用脚本生成CA证书、etcd服务器证书以及私钥

mkdir /opt/k8s
cd /opt/k8s/
chmod +x etcd-cert.sh etcd.sh
mkdir /opt/k8s/etcd-cert
mv etcd-cert.sh etcd-cert/
cd /opt/k8s/etcd-cert/
./etcd-cert.sh

etcd-cert.sh脚本:

#!/bin/bash

# 配置证书生成策略
cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "www": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

# 生成根证书的请求文件
cat > ca-csr.json <<EOF
{
    "CN": "etcd",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

# 使用 CSR 文件生成根证书和私钥
cfssl gencert -initca ca-csr.json | cfssljson -bare ca

# 生成服务器证书的请求文件
cat > server-csr.json <<EOF
{
    "CN": "etcd",
    "hosts": [
    "192.168.1.11",
    "192.168.1.33",
    "192.168.1.44"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing"
        }
    ]
}
EOF

# 使用根证书签发服务器证书和私钥
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server

上传etcd-v3.4.9-linux-amd64.tar.gz 到/opt/k8s/后启动etcd服务

cd /opt/k8s/
tar zxvf etcd-v3.4.9-linux-amd64.tar.gz
mkdir -p /opt/etcd/{cfg,bin,ssl}
cd /opt/k8s/etcd-v3.4.9-linux-amd64/
mv etcd etcdctl /opt/etcd/bin/
cp /opt/k8s/etcd-cert/*.pem /opt/etcd/ssl/
cd /opt/k8s/
./etcd.sh etcd01 192.168.1.11 etcd02=https://192.168.1.33:2380,etcd03=https://192.168.1.44:2380

把etcd相关证书文件、命令文件和服务管理文件全部拷贝到另外两个etcd集群节点

scp -r /opt/etcd/ root@192.168.1.33:/opt/
scp -r /opt/etcd/ root@192.168.1.44:/opt/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.33:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/etcd.service root@192.168.1.44:/usr/lib/systemd/system/

在node节点分别修改etcd配置文件并启动etcd

vim /opt/etcd/cfg/etcd
systemctl start etcd
systemctl enable etcd 
systemctl status etcd

检查etcd集群状态

ETCDCTL_API=3   /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379" endpoint health --write-out=table

这个命令用于检查 etcd 集群中各个节点的健康状态,并以表格形式输出。

  • ETCDCTL_API=3:设置 etcdctl 的 API 版本为 3。
  • /opt/etcd/bin/etcdctl:指定 etcdctl 的路径。
  • --cacert=/opt/etcd/ssl/ca.pem:指定根证书文件的路径,用于验证 etcd 服务器证书的有效性。
  • --cert=/opt/etcd/ssl/server.pem:指定客户端证书的路径,用于与 etcd 服务器进行双向身份验证。
  • --key=/opt/etcd/ssl/server-key.pem:指定客户端私钥的路径,用于与 etcd 服务器进行双向身份验证。
  • --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379":指定 etcd 集群的各个节点的地址和端口。
  • endpoint health:检查 etcd 集群中各个节点的健康状态。
  • --write-out=table:以表格形式输出结果。
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379" endpoint status --write-out=table

这个命令用于获取 etcd 集群中各个节点的状态,并以表格形式输出。

  • ETCDCTL_API=3:设置 etcdctl 的 API 版本为 3。
  • /opt/etcd/bin/etcdctl:指定 etcdctl 的路径。
  • --cacert=/opt/etcd/ssl/ca.pem:指定根证书文件的路径,用于验证 etcd 服务器证书的有效性。
  • --cert=/opt/etcd/ssl/server.pem:指定客户端证书的路径,用于与 etcd 服务器进行双向身份验证。
  • --key=/opt/etcd/ssl/server-key.pem:指定客户端私钥的路径,用于与 etcd 服务器进行双向身份验证。
  • --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379":指定 etcd 集群的各个节点的地址和端口。
  • endpoint status:获取 etcd 集群中各个节点的状态。
  • --write-out=table:以表格形式输出结果。
ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379" --write-out=table member list

这个命令用于列出 etcd 集群中的成员,并以表格形式输出。

  • ETCDCTL_API=3:设置 etcdctl 的 API 版本为 3。
  • /opt/etcd/bin/etcdctl:指定 etcdctl 的路径。
  • --cacert=/opt/etcd/ssl/ca.pem:指定根证书文件的路径,用于验证 etcd 服务器证书的有效性。
  • --cert=/opt/etcd/ssl/server.pem:指定客户端证书的路径,用于与 etcd 服务器进行双向身份验证。
  • --key=/opt/etcd/ssl/server-key.pem:指定客户端私钥的路径,用于与 etcd 服务器进行双向身份验证。
  • --endpoints="https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379":指定 etcd 集群的各个节点的地址和端口。
  • member list:列出 etcd 集群中的成员。
  • --write-out=table:以表格形式输出结果。

部署master:

在/opt/k8s/目录中准备admin.sh、apiserver.sh、controller-manager.sh、scheduler.sh、k8s-sert.sh,kubernetes-server-linux-amd64.tar.gz

admin.sh

#!/bin/bash
mkdir /root/.kube
KUBE_CONFIG="/root/.kube/config"
KUBE_APISERVER="https://192.168.1.11:6443"

cd /opt/k8s/k8s-cert/

kubectl config set-cluster kubernetes \
  --certificate-authority=/opt/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials cluster-admin \
  --client-certificate=./admin.pem \
  --client-key=./admin-key.pem \
  --embed-certs=true \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
  --cluster=kubernetes \
  --user=cluster-admin \
  --kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}

apiserver.sh

#!/bin/bash
#example: apiserver.sh your_master_ip https://your_etcd01_ip:2379,https://your_etcd02_ip:2379,https://your_etcd03_ip:2379
#创建 kube-apiserver 启动参数配置文件
MASTER_ADDRESS=$1
ETCD_SERVERS=$2

cat >/opt/kubernetes/cfg/kube-apiserver <<EOF
KUBE_APISERVER_OPTS="--logtostderr=false  \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--etcd-servers=${ETCD_SERVERS} \\
--bind-address=${MASTER_ADDRESS} \\
--secure-port=6443 \\
--advertise-address=${MASTER_ADDRESS} \\
--allow-privileged=true \\
--service-cluster-ip-range=10.0.0.0/24 \\
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \\
--authorization-mode=RBAC,Node \\
--enable-bootstrap-token-auth=true \\
--token-auth-file=/opt/kubernetes/cfg/token.csv \\
--service-node-port-range=30000-50000 \\
--kubelet-client-certificate=/opt/kubernetes/ssl/apiserver.pem \\
--kubelet-client-key=/opt/kubernetes/ssl/apiserver-key.pem \\
--tls-cert-file=/opt/kubernetes/ssl/apiserver.pem  \\
--tls-private-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--service-account-issuer=api \\
--service-account-signing-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--etcd-cafile=/opt/etcd/ssl/ca.pem \\
--etcd-certfile=/opt/etcd/ssl/server.pem \\
--etcd-keyfile=/opt/etcd/ssl/server-key.pem \\
--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \\
--proxy-client-cert-file=/opt/kubernetes/ssl/apiserver.pem \\
--proxy-client-key-file=/opt/kubernetes/ssl/apiserver-key.pem \\
--requestheader-allowed-names=kubernetes \\
--requestheader-extra-headers-prefix=X-Remote-Extra- \\
--requestheader-group-headers=X-Remote-Group \\
--requestheader-username-headers=X-Remote-User \\
--enable-aggregator-routing=true \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/opt/kubernetes/logs/k8s-audit.log"
EOF

#--logtostderr=true:启用日志。输出日志到标准错误控制台,不输出到文件
#--v=4:日志等级。指定输出日志的级别,v=4为调试级别详细输出
#--etcd-servers:etcd集群地址。指定etcd服务器列表(格式://ip:port),逗号分隔
#--bind-address:监听地址。指定 HTTPS 安全接口的监听地址,默认值0.0.0.0
#--secure-port:https安全端口。指定 HTTPS 安全接口的监听端口,默认值6443
#--advertise-address:集群通告地址。通过该 ip 地址向集群其他节点公布 api server 的信息,必须能够被其他节点访问
#--allow-privileged=true:启用授权。允许拥有系统特权的容器运行,默认值false
#--service-cluster-ip-range:Service虚拟IP地址段。指定 Service Cluster IP 地址段
#--enable-admission-plugins:准入控制模块。kuberneres集群的准入控制机制,各控制模块以插件的形式依次生效,集群时必须包含ServiceAccount,运行在认证(Authentication)、授权(Authorization)之后,Admission Control是权限认证链上的最后一环, 对请求API资源对象进行修改和校验
#--authorization-mode:认证授权,启用RBAC授权和节点自管理。在安全端口使用RBAC,Node授权模式,未通过授权的请求拒绝,默认值AlwaysAllow。RBAC是用户通过角色与权限进行关联的模式;Node模式(节点授权)是一种特殊用途的授权模式,专门授权由kubelet发出的API请求,在进行认证时,先通过用户名、用户分组验证是否是集群中的Node节点,只有是Node节点的请求才能使用Node模式授权
#--enable-bootstrap-token-auth:启用TLS bootstrap机制。在apiserver上启用Bootstrap Token 认证
#--token-auth-file=/opt/kubernetes/cfg/token.csv:指定bootstrap token认证文件路径
#--service-node-port-range:指定 Service  NodePort 的端口范围,默认值30000-32767
#–-kubelet-client-xxx:apiserver访问kubelet客户端证书
#--tls-xxx-file:apiserver https证书
#1.20版本必须加的参数:–-service-account-issuer,–-service-account-signing-key-file
#--etcd-xxxfile:连接Etcd集群证书
#–-audit-log-xxx:审计日志
#启动聚合层相关配置:–requestheader-client-ca-file,–proxy-client-cert-file,–proxy-client-key-file,–requestheader-allowed-names,–requestheader-extra-headers-prefix,–requestheader-group-headers,–requestheader-username-headers,–enable-aggregator-routing


#创建 kube-apiserver.service 服务管理文件
cat >/usr/lib/systemd/system/kube-apiserver.service <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-apiserver
ExecStart=/opt/kubernetes/bin/kube-apiserver \$KUBE_APISERVER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kube-apiserver
systemctl restart kube-apiserver

controller-manager.sh

#!/bin/bash
##创建 kube-controller-manager 启动参数配置文件
MASTER_ADDRESS=$1

cat >/opt/kubernetes/cfg/kube-controller-manager <<EOF
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--kubeconfig=/opt/kubernetes/cfg/kube-controller-manager.kubeconfig \\
--bind-address=127.0.0.1 \\
--allocate-node-cidrs=true \\
--cluster-cidr=10.244.0.0/16 \\
--service-cluster-ip-range=10.0.0.0/24 \\
--cluster-signing-cert-file=/opt/kubernetes/ssl/ca.pem \\
--cluster-signing-key-file=/opt/kubernetes/ssl/ca-key.pem  \\
--root-ca-file=/opt/kubernetes/ssl/ca.pem \\
--service-account-private-key-file=/opt/kubernetes/ssl/ca-key.pem \\
--cluster-signing-duration=87600h0m0s"
EOF

#––leader-elect:当该组件启动多个时,自动选举(HA)
#-–kubeconfig:连接 apiserver 用的配置文件,用于识别 k8s 集群
#--cluster-cidr=10.244.0.0/16:pod资源的网段,需与pod网络插件的值设置一致。通常,Flannel网络插件的默认为10.244.0.0/16,Calico插件的默认值为192.168.0.0/16
#--cluster-signing-cert-file/–-cluster-signing-key-file:自动为kubelet颁发证书的CA,与apiserver保持一致。指定签名的CA机构根证书,用来签名为 TLS BootStrapping 创建的证书和私钥
#--root-ca-file:指定根CA证书文件路径,用来对 kube-apiserver 证书进行校验,指定该参数后,才会在 Pod 容器的 ServiceAccount 中放置该 CA 证书文件
#--experimental-cluster-signing-duration:设置为 TLS BootStrapping 签署的证书有效时间为10年,默认为1年


##生成kube-controller-manager证书
cd /opt/k8s/k8s-cert/
#创建证书请求文件
cat > kube-controller-manager-csr.json << EOF
{
  "CN": "system:kube-controller-manager",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing", 
      "ST": "BeiJing",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
EOF

#生成证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager

#生成kubeconfig文件
KUBE_CONFIG="/opt/kubernetes/cfg/kube-controller-manager.kubeconfig"
KUBE_APISERVER="https://192.168.1.11:6443"

kubectl config set-cluster kubernetes \
  --certificate-authority=/opt/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-controller-manager \
  --client-certificate=./kube-controller-manager.pem \
  --client-key=./kube-controller-manager-key.pem \
  --embed-certs=true \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-controller-manager \
  --kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}


##创建 kube-controller-manager.service 服务管理文件
cat >/usr/lib/systemd/system/kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-controller-manager
ExecStart=/opt/kubernetes/bin/kube-controller-manager \$KUBE_CONTROLLER_MANAGER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl restart kube-controller-manager

scheduler.sh

#!/bin/bash
##创建 kube-scheduler 启动参数配置文件
MASTER_ADDRESS=$1

cat >/opt/kubernetes/cfg/kube-scheduler <<EOF
KUBE_SCHEDULER_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--leader-elect=true \\
--kubeconfig=/opt/kubernetes/cfg/kube-scheduler.kubeconfig \\
--bind-address=127.0.0.1"
EOF

#-–kubeconfig:连接 apiserver 用的配置文件,用于识别 k8s 集群
#--leader-elect=true:当该组件启动多个时,自动启动 leader 选举
#k8s中Controller-Manager和Scheduler的选主逻辑:k8s中的etcd是整个集群所有状态信息的存储,涉及数据的读写和多个etcd之间数据的同步,对数据的一致性要求严格,所以使用较复杂的 raft 算法来选择用于提交数据的主节点。而 apiserver 作为集群入口,本身是无状态的web服务器,多个 apiserver 服务之间直接负载请求并不需要做选主。Controller-Manager 和 Scheduler 作为任务类型的组件,比如 controller-manager 内置的 k8s 各种资源对象的控制器实时的 watch apiserver 获取对象最新的变化事件做期望状态和实际状态调整,调度器watch未绑定节点的pod做节点选择,显然多个这些任务同时工作是完全没有必要的,所以 controller-manager 和 scheduler 也是需要选主的,但是选主逻辑和 etcd 不一样的,这里只需要保证从多个 controller-manager 和 scheduler 之间选出一个 leader 进入工作状态即可,而无需考虑它们之间的数据一致和同步。


##生成kube-scheduler证书
cd /opt/k8s/k8s-cert/
#创建证书请求文件
cat > kube-scheduler-csr.json << EOF
{
  "CN": "system:kube-scheduler",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
EOF

#生成证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler

#生成kubeconfig文件
KUBE_CONFIG="/opt/kubernetes/cfg/kube-scheduler.kubeconfig"
KUBE_APISERVER="https://192.168.1.11:6443"

kubectl config set-cluster kubernetes \
  --certificate-authority=/opt/kubernetes/ssl/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-credentials kube-scheduler \
  --client-certificate=./kube-scheduler.pem \
  --client-key=./kube-scheduler-key.pem \
  --embed-certs=true \
  --kubeconfig=${KUBE_CONFIG}
kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-scheduler \
  --kubeconfig=${KUBE_CONFIG}
kubectl config use-context default --kubeconfig=${KUBE_CONFIG}


##创建 kube-scheduler.service 服务管理文件
cat >/usr/lib/systemd/system/kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-scheduler
ExecStart=/opt/kubernetes/bin/kube-scheduler \$KUBE_SCHEDULER_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kube-scheduler
systemctl restart kube-scheduler

k8s-sert.sh

#!/bin/bash
cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

#生成CA证书和私钥(根证书和私钥)
cat > ca-csr.json <<EOF
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing",
      	    "O": "k8s",
            "OU": "System"
        }
    ]
}
EOF

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -


#-----------------------
#生成 apiserver 的证书和私钥(apiserver和其它k8s组件通信使用)
#hosts中将所有可能作为 apiserver 的 ip 添加进去,后面 keepalived 使用的 VIP 也要加入
cat > apiserver-csr.json <<EOF
{
    "CN": "kubernetes",
    "hosts": [
      "10.0.0.1",
      "127.0.0.1",
      "192.168.1.11",
      "192.168.1.22",
      "192.168.1.100",
      "192.168.1.55",
      "192.168.1.66",
      "kubernetes",
      "kubernetes.default",
      "kubernetes.default.svc",
      "kubernetes.default.svc.cluster",
      "kubernetes.default.svc.cluster.local"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes apiserver-csr.json | cfssljson -bare apiserver


#-----------------------
#生成 kubectl 连接集群的证书和私钥,具有admin权限
cat > admin-csr.json <<EOF
{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin


#-----------------------
#生成 kube-proxy 的证书和私钥
cat > kube-proxy-csr.json <<EOF
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
chmod +x *.sh
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}
mkdir /opt/k8s/k8s-cert
mv /opt/k8s/k8s-cert.sh /opt/k8s/k8s-cert
cd /opt/k8s/k8s-cert/
./k8s-cert.sh

cp ca*pem apiserver*pem /opt/kubernetes/ssl/
cd /opt/k8s/
tar zxvf kubernetes-server-linux-amd64.tar.gz
cd /opt/k8s/kubernetes/server/bin
cp kube-apiserver kubectl kube-controller-manager kube-scheduler /opt/kubernetes/bin/
ln -s /opt/kubernetes/bin/* /usr/local/bin/
cd /opt/k8s/
vim token.sh
#!/bin/bash
#获取随机数前16个字节内容,以十六进制格式输出,并删除其中空格
BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ') 
#生成 token.csv 文件,按照 Token序列号,用户名,UID,用户组 的格式生成
cat > /opt/kubernetes/cfg/token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF
chmod +x token.sh
./token.sh
cat /opt/kubernetes/cfg/token.csv
cd /opt/k8s/
./apiserver.sh 192.168.1.11 https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379
ps aux | grep kube-apiserver
netstat -natp | grep 6443
cd /opt/k8s/
#启动 scheduler 服务
./scheduler.sh
ps aux | grep kube-scheduler
#启动 controller-manager 服务
./controller-manager.sh
ps aux | grep kube-controller-manager
#生成kubectl连接集群的kubeconfig文件
./admin.sh
#通过kubectl工具查看当前集群组件状态
kubectl get cs

部署node:

在所有node操作

创建kubernetes工作目录

mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}

准备kubelet.sh、proxy.sh

kubelet.sh

#!/bin/bash

NODE_ADDRESS=$1
DNS_SERVER_IP=${2:-"10.0.0.2"}

#创建 kubelet 启动参数配置文件
cat >/opt/kubernetes/cfg/kubelet <<EOF
KUBELET_OPTS="--logtostderr=false \\
--v=2 \\
--log-dir=/opt/kubernetes/logs \\
--hostname-override=${NODE_ADDRESS} \\
--network-plugin=cni \\
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \\
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \\
--config=/opt/kubernetes/cfg/kubelet.config \\
--cert-dir=/opt/kubernetes/ssl \\
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"
EOF

#--hostname-override:指定kubelet节点在集群中显示的主机名或IP地址,默认使用主机hostname;kube-proxy和kubelet的此项参数设置必须完全一致
#--network-plugin:启用CNI
#--kubeconfig:指定kubelet.kubeconfig文件位置,当前为空路径,会自动生成,用于如何连接到apiserver,里面含有kubelet证书,master授权完成后会在node节点上生成 kubelet.kubeconfig 文件
#--bootstrap-kubeconfig:指定连接 apiserver 的 bootstrap.kubeconfig 文件
#--config:指定kubelet配置文件的路径,启动kubelet时将从此文件加载其配置
#--cert-dir:指定master颁发的kubelet证书生成目录
#--pod-infra-container-image:指定Pod基础容器(Pause容器)的镜像。Pod启动的时候都会启动一个这样的容器,每个pod之间相互通信需要Pause的支持,启动Pause需要Pause基础镜像


#----------------------
#创建kubelet配置文件(该文件实际上就是一个yml文件,语法非常严格,不能出现tab键,冒号后面必须要有空格,每行结尾也不能有空格)
cat >/opt/kubernetes/cfg/kubelet.config <<EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
address: ${NODE_ADDRESS}
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS:
- ${DNS_SERVER_IP} 
clusterDomain: cluster.local
failSwapOn: false
authentication:
  anonymous:
    enabled: true
EOF

#PS:当命令行参数与此配置文件(kubelet.config)有相同的值时,就会覆盖配置文件中的该值。


#----------------------
#创建 kubelet.service 服务管理文件
cat >/usr/lib/systemd/system/kubelet.service <<EOF
[Unit]
Description=Kubernetes Kubelet
After=docker.service
Requires=docker.service

[Service]
EnvironmentFile=/opt/kubernetes/cfg/kubelet
ExecStart=/opt/kubernetes/bin/kubelet \$KUBELET_OPTS
Restart=on-failure
KillMode=process

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kubelet
systemctl restart kubelet

proxy.sh

#!/bin/bash

NODE_ADDRESS=$1

#创建 kube-proxy 启动参数配置文件
cat >/opt/kubernetes/cfg/kube-proxy <<EOF
KUBE_PROXY_OPTS="--logtostderr=true \\
--v=4 \\
--hostname-override=${NODE_ADDRESS} \\
--cluster-cidr=172.17.0.0/16 \\
--proxy-mode=ipvs \\
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"
EOF

#--hostnameOverride: 参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 Node,从而不会创建任何 ipvs 规则
#--cluster-cidr:指定 Pod 网络使用的聚合网段,Pod 使用的网段和 apiserver 中指定的 service 的 cluster ip 网段不是同一个网段。 kube-proxy 根据 --cluster-cidr 判断集群内部和外部流量,指定 --cluster-cidr 选项后 kube-proxy 才会对访问 Service IP 的请求做 SNAT,即来自非 Pod 网络的流量被当成外部流量,访问 Service 时需要做 SNAT。
#--proxy-mode:指定流量调度模式为ipvs模式,可添加--ipvs-scheduler选项指定ipvs调度算法(rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq)
#--kubeconfig: 指定连接 apiserver 的 kubeconfig 文件	


#----------------------
#创建 kube-proxy.service 服务管理文件
cat >/usr/lib/systemd/system/kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Proxy
After=network.target

[Service]
EnvironmentFile=-/opt/kubernetes/cfg/kube-proxy
ExecStart=/opt/kubernetes/bin/kube-proxy \$KUBE_PROXY_OPTS
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable kube-proxy
systemctl restart kube-proxy
chmod +x kubelet.sh proxy.sh

在 master01 节点上操作

cd /opt/k8s/kubernetes/server/bin
scp kubelet kube-proxy root@192.168.1.33:/opt/kubernetes/bin/
scp kubelet kube-proxy root@192.168.1.44:/opt/kubernetes/bin/
mkdir /opt/k8s/kubeconfig
cd /opt/k8s/kubeconfig

在/opt/k8s/kubeconfig/目录下准备kubeconfig.sh

kubeconfig.sh

#!/bin/bash
#example: kubeconfig 192.168.1.11 /opt/k8s/k8s-cert/
#创建bootstrap.kubeconfig文件
#该文件中内置了 token.csv 中用户的 Token,以及 apiserver CA 证书;kubelet 首次启动会加载此文件,使用 apiserver CA 证书建立与 apiserver 的 TLS 通讯,使用其中的用户 Token 作为身份标识向 apiserver 发起 CSR 请求

BOOTSTRAP_TOKEN=$(awk -F ',' '{print $1}' /opt/kubernetes/cfg/token.csv)
APISERVER=$1
SSL_DIR=$2

export KUBE_APISERVER="https://$APISERVER:6443"

# 设置集群参数
kubectl config set-cluster kubernetes \
  --certificate-authority=$SSL_DIR/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=bootstrap.kubeconfig
#--embed-certs=true:表示将ca.pem证书写入到生成的bootstrap.kubeconfig文件中

# 设置客户端认证参数,kubelet 使用 bootstrap token 认证
kubectl config set-credentials kubelet-bootstrap \
  --token=${BOOTSTRAP_TOKEN} \
  --kubeconfig=bootstrap.kubeconfig

# 设置上下文参数
kubectl config set-context default \
  --cluster=kubernetes \
  --user=kubelet-bootstrap \
  --kubeconfig=bootstrap.kubeconfig

# 使用上下文参数生成 bootstrap.kubeconfig 文件
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig

#----------------------

#创建kube-proxy.kubeconfig文件
# 设置集群参数
kubectl config set-cluster kubernetes \
  --certificate-authority=$SSL_DIR/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-proxy.kubeconfig

# 设置客户端认证参数,kube-proxy 使用 TLS 证书认证
kubectl config set-credentials kube-proxy \
  --client-certificate=$SSL_DIR/kube-proxy.pem \
  --client-key=$SSL_DIR/kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig

# 设置上下文参数
kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig

# 使用上下文参数生成 kube-proxy.kubeconfig 文件
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
chmod +x kubeconfig.sh
./kubeconfig.sh 192.168.1.11 /opt/k8s/k8s-cert/
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@192.168.1.33:/opt/kubernetes/cfg/
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@192.168.1.44:/opt/kubernetes/cfg/
kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap

若执行失败,可先给kubectl绑定默认cluster-admin管理员集群角色,授权集群操作权限
kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous

在node01节点操作

cd /opt/
./kubelet.sh 192.168.1.33
ps aux | grep kubelet

在 master01 节点上操作

kubectl get csr

kubectl certificate approve node-csr-duiobEzQ0R93HsULoS9NT9JaQylMmid_nBF3Ei3NtFE

kubectl get csr

在 node01 节点上操作

for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
cd /opt/
./proxy.sh 192.168.1.33
ps aux | grep kube-proxy

部署 Calico网络:

在 master01 节点上操作

准备calico.yaml 文件到 /opt/k8s 目录中

           # - name: CALICO_IPV4POOL_CIDR
            #   value: "10.244.0.0/16"

修改里面定义 Pod 的网络(CALICO_IPV4POOL_CIDR),需与前面 kube-controller-manager 配置文件指定的 cluster-cidr 网段一样

kubectl apply -f calico.yaml
kubectl get pods -n kube-system
kubectl get nodes

部署node02:

在node01操作

cd /opt/
scp kubelet.sh proxy.sh root@192.168.1.44:/opt/
scp -r /opt/cni root@192.168.1.44:/opt/

在node02操作

cd /opt/
chmod +x kubelet.sh
./kubelet.sh 192.168.1.44

在 master01 节点上操作

kubectl get csr
kubectl certificate approve node-csr-nh4DGjA-xNcE_dJ0blI6HTgz-XcqTkD5MFiGQQ9mEoQ
kubectl get csr

在 node02 节点上操作

for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done
cd /opt/
chmod +x proxy.sh
./proxy.sh 192.168.1.44

在 master01 节点上操作

kubectl get nodes

部署 CoreDNS

在所有 node 节点上操作

上传 coredns.tar 到 /opt 目录中

cd /opt
docker load -i coredns.tar

在 master01 节点上操作

上传 coredns.yaml 文件到 /opt/k8s 目录中,部署 CoreDNS 

cd /opt/k8s
kubectl apply -f coredns.yaml
kubectl get pods -n kube-system 

DNS 解析测试

kubectl run -it --rm dns-test --image=busybox:1.28.4 sh

如果出现以下报错
[root@master01 k8s]# kubectl run -it  --image=busybox:1.28.4 sh
If you don't see a command prompt, try pressing enter.
Error attaching, falling back to logs: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
Error from server (Forbidden): Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy) ( pods/log sh)

需要添加 rbac的权限  直接使用kubectl绑定  clusteradmin 管理员集群角色  授权操作权限

[root@master01 k8s]# kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/cluster-system-anonymous created

master02 节点部署 :

从 master01 节点上拷贝证书文件、各master组件的配置文件和服务管理文件到 master02 节点

scp -r /opt/etcd/ root@192.168.1.22:/opt/
scp -r /opt/kubernetes/ root@192.168.1.22:/opt
scp -r /root/.kube root@192.168.1.22:/root
scp /usr/lib/systemd/system/{kube-apiserver,kube-controller-manager,kube-scheduler}.service root@192.168.1.22:/usr/lib/systemd/system/

在master02上修改配置文件kube-apiserver中的IP

vim /opt/kubernetes/cfg/kube-apiserver
--etcd-servers=https://192.168.1.11:2379,https://192.168.1.33:2379,https://192.168.1.44:2379 \
--bind-address=192.168.1.22 \
--secure-port=6443 \
--advertise-address=192.168.1.22 \
--allow-privileged=true \

在 master02 节点上启动各服务并设置开机自启

systemctl start kube-apiserver.service
systemctl enable kube-apiserver.service
systemctl start kube-controller-manager.service
systemctl enable kube-controller-manager.service
systemctl start kube-scheduler.service
systemctl enable kube-scheduler.service

查看node节点状态

ln -s /opt/kubernetes/bin/* /usr/local/bin/
kubectl get nodes

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/629032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

困惑点记录

【第十章 总结思考】CIM之我见 - 知乎

Java开发大厂面试第03讲:线程的状态有哪些?它是如何工作的?

线程&#xff08;Thread&#xff09;是并发编程的基础&#xff0c;也是程序执行的最小单元&#xff0c;它依托进程而存在。一个进程中可以包含多个线程&#xff0c;多线程可以共享一块内存空间和一组系统资源&#xff0c;因此线程之间的切换更加节省资源、更加轻量化&#xff0…

C++11 新特性 常量表达式 constexpr

为了解决常量无法确定的问题&#xff0c;C11在新标准中提出了关键字constexpr&#xff0c;它能够有效地定义常量表达式&#xff0c;并且达到类型安全、可移植、方便库和嵌入式系统开发的目的。 一、常量的不确定性 在C11标准以前&#xff0c;我们没有一种方法能够有效地要求一…

短视频矩阵系统/源码----可视化剪辑技术独家开发

现阶段市面上大多矩阵软件都非常程序化且需要使用者具有较强的逻辑思维能力或剪辑经验&#xff0c;这使得一些个人、团队、企业在使用时无形中增加了学习成本&#xff0c;剪辑出来的效果大多不尽如人意&#xff0c;发出来的视频没有流量&#xff0c;根本达不到预期效果。 如何提…

汽车工厂安灯系统能够快速知晓生产现场的状况

汽车工厂是一个庞大的生产系统&#xff0c;其中有数以百计的工人、机器和设备在不断运转&#xff0c;以确保汽车的生产顺利进行。在如此复杂的生产环境中&#xff0c;安全是至关重要的&#xff0c;而安灯系统正是一个能够帮助汽车工厂快速知晓生产现场状况的重要工具。 安灯系统…

海外云手机的运作原理和适用场景

海外云手机是一种基于云计算技术的虚拟手机服务&#xff0c;通过将手机操作系统和应用程序托管在远程服务器上&#xff0c;实现用户可以通过互联网连接来使用和管理手机功能&#xff0c;而无需实际拥有物理手机。以下是有关海外云手机的相关信息&#xff1a; 海外云手机的运作原…

HCIP【Hybird实验】

目录 一、实验拓扑图&#xff1a; 二、实验要求&#xff1a; 三、实验思路&#xff1a; 四、实验过程&#xff1a; 1、配置PC的IP地址&#xff08;不用配置网关&#xff0c;这个拓扑图没有使用到三层设备&#xff09; 2、交换机配置 3、PC间进行测试&#xff1a; 一、实…

大模型来了,创业者怎么做出好产品?

大模型的问世惊艳了人们的目光&#xff0c;打开了对AI想象力——生成未来&#xff0c;是谁的未来&#xff1f; “电的发明并不是只能让爱迪生的公司成为全球最大公司&#xff0c;而是为众多电器制造商也提供了巨大的商机。从人类科技史的角度来看&#xff0c;应用层面的价值往…

基于国产LoRa的智慧农业解决方案--ASR6601、SX1278

我国《数字乡村发展战略纲要》明确指出“要推进农业数字化转型”&#xff0c;加快推广云计算、大数据、物联网、人工智能在农业生产经营管理中的运用。 然而&#xff0c;目前我国的农业数字化转型还面临着诸多挑战。我国整体农业机械化程度和自动化控制水平仍然较低。由于农田面…

[图解]EA从数据库逆向得到分析类模型-01

1 00:00:00,840 --> 00:00:02,400 今天&#xff0c;我们来说一下 2 00:00:02,670 --> 00:00:06,320 一个最近几天不止一个同学问的问题 3 00:00:06,490 --> 00:00:11,410 就是说&#xff0c;怎样把一个数据库 4 00:00:13,740 --> 00:00:16,720 转到分析类图 5 …

so-vits-svc:AI翻唱,语音克隆

前言 这个项目是为了让开发者最喜欢的动画角色唱歌而开发的&#xff0c;任何涉及真人的东西都与开发者的意图背道而驰。 项目地址&#xff1a;https://github.com/svc-develop-team/so-vits-svc/blob/4.1-Stable/README_zh_CN.md 安装 可以自行配置&#xff0c;应该也不难 …

Python中合并多个CSV数据集的技术实践

目录 一、引言 二、准备工作 三、读取CSV文件 四、数据预处理 五、合并数据集 六、错误处理与调试 七、案例分析 八、总结 一、引言 在数据处理和分析的过程中&#xff0c;我们经常需要处理多个CSV&#xff08;逗号分隔值&#xff09;文件&#xff0c;并将它们合并…

如何快速将视频做成二维码?扫描二维码播放视频的制作方法

视频二维码的用途越来越多&#xff0c;比如常见的有产品展示、企业宣传、教程说明、个人展示等都可以生成二维码&#xff0c;通过扫码在手机或者其他设备上预览内容&#xff0c;从而提升其他人获取视频的速度&#xff0c;实现内容的快速分享。 对于有制作视频二维码需求的小伙…

Java面试八股之Collection和Collections的区别

Java中Collection和Collections的区别 Collection 是一个接口&#xff0c;位于 java.util 包中&#xff0c;它是 Java 集合框架的顶层接口之一&#xff0c;代表了一组对象的集合。Collection 接口定义了所有集合类型&#xff08;如 List、Set、Queue 等&#xff09;所共有的基…

深度解析 Spring 源码:解密AOP切点和通知的实现机制

文章目录 深度解析 Spring 源码&#xff1a;解密AOP切点和通知的实现机制一、Spring AOP的基础知识1.1 AOP的核心概念&#xff1a;切点、通知、切面等1.2 Spring AOP与传统AOP的区别和优势 二、深入分析切点和通知的实现2.1 研究 Pointcut 接口及其实现类2.1.1 Pointcut 接口2.…

java springboot连接sqlserver使用

pom.xml增加sqlserver驱动 <dependency><groupId>com.microsoft.sqlserver</groupId><artifactId>mssql-jdbc</artifactId><version>9.4.0.jre8</version></dependency>application.yml配置文件 server:port: 9001 #spring: …

了解 Robot Framework :接口自动化测试教程!

开源自动化测试利器&#xff1a;Robot Framework Robot Framework 是一个用于实现自动化测试和机器人流程自动化&#xff08;RPA&#xff09;的开放源代码框架。它由一个名为 Robot Framework Foundation 的组织得到推广&#xff0c;得到了多家领军企业在软件开发中的广泛应用。…

HL7协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.介绍2.传输协议规范2.1. MLLP2.1.1. 数据头定义2.1.2. 转义字符集 2.2. 规范说明2.3. 消息格式说明 3.HL7结构介绍3.1. 患者建档&#xff08;ADT^A28&#xff09;…

​python使用selenium进行Web自动化测试​

什么是selenium Selenium 是 ThoughtWorks 提供的一个强大的基于浏览器的 Selenium 是一个用于 Web 应用程序测试的工具&#xff0c;测试直接自动运行在浏览器中&#xff0c;就像真正的用户在手工操作一样。支持的浏览器包括 IE、Chrome 和 Firefox 等。这个工具的主要功能包…

Redis 源码安装和入门介绍

Linux下的redis源码安装 redis介绍 Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c;…