第一章 k8s核心概念
1.1 k8s
1.1.1 k8s的概念

  1. k8s是一款容器编排工具, 用于管理docker容器, 也是云原生架构的标准容器调度系统
    第二章 k8s集群
    2.1 k8s-集群组成
    2.1.1 master节点
  2. 作用: 负责容器资源调度, 控制副本, 为集群提供统一的访问入口, 来管理node节点
    2.1.2 node节点
  3. 作用: 承载pod的运行, 为master节点汇报容器状态
    2.2 k8s资源组件
  4. pod
  5. deployment
  6. deamon set
  7. corn job
  8. service
  9. ingress
  10. configmap
  11. secret
  12. pv/pvc
  13. namespace
    注意:
  14. pod中至少有一个容器, 是pause, 用于管理pod网络
    2.3 master节点组件
  15. api server: 是k8s集群的入口, 封装了对核心对象的增删改查操3作, 负责组件的认证, 访问控制以及对接etcd
  16. scheduler(调度器): 负责管理pod调度绑定, 根据节点资源的使用情况, 将pod与最优node进行绑定
  17. controller-manager(控制器集合): 维持集群的节点状态, 管理故障节点的pod转移, deployment副本数量, 账号权限的自动修复
  18. etcd数据库: 用于保存集群的配置信息与元数据(节点信息, pod, service规则)
    2.4 node节点组件
  19. kubelet: 管理宿主机pod中的容器, 接收aps server的pod官不理请求, 监控容器的运行状态并上报api server
  20. kube proxy: 实现service的服务发现和负载均衡
  21. docker engine: 管理pod中的容器
  22. flanneld: 管理pod网络, 让每个pod有独立的ip, 实现跨节点的通信
    注意:
  23. k8s支持的容器管理有docker和containerd(主流)
    2.5 源码搭建k8s集群
    2.5.1 环境
    192.168.255.130 master etcd: master
    192.168.255.132 node etcd: node1
    192.168.255.133 node etcd: node2
    2.5.2 关闭防火墙与selinux
systemctl disable firewalld
sed -ri 's/SELINUX=enforcing/SELINUX=disabled/' /etc/sysconfig/selinux
setenforce 0```
2.5.3 配置域名解析并修改主机名
```YAML
cat >> /etc/hosts << EOF
192.168.255.130 master etcd01
192.168.255.132 node1 etcd02
192.168.255.133 node2 etcd03
EOF
hostnamectl set-hostname master
su
hostnamectl set-hostname node1
su
hostnamectl set-hostname node2
su```
2.5.4 部署etcd数据库集群
1. 下载cfssl证书工具
```YAML
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
#为文件添加执行权限
chmod a+x ./cfssl*amd64
#将文件移动到bin目录
mv cfssl_linux-amd64 /usr/local/bin/cfssl
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinf```
2. 生成etc数据库集群的ssl证书
```YAML
cd /root
mkdir cert
cd cert
#配置ca中心
vim ./ca-config.json
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "www": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
#生成ca中心的证书请求文件
vim ./ca-csr.json
{   
    "CN": "etcd CA",
    "key": {
        "algo": "rsa",
        "size": 2048
        },
    "names": [
        {
            "C": "CN",    
            "L": "Beijing",
            "ST": "Beijing"
         }
    ]
}
#生成服务器的证书请求文件
vim ./server-csr.json
{
    "CN": "etcd",
    "hosts": [
    "192.168.255.130",
    "192.168.255.132",
    "192.168.255.133"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing"
        }
    ]
}```
3. 生成证书
```YAML
cd /root/cert
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www server-csr.json | cfssljson -bare server```
4. 安装etcd并配置, 每个节点都做
```YAML
#130,132,133都如此操作
mkdir -p /opt/etcd/{bin,cfg,ssl}
#解压安装包
tar -zxvf ./etcd-v3.2.12-linux-amd64.tar.gz
mv ./etcd-v3.2.12-linux-amd64/{etcd,etcdctl} /opt/etcd/bin
# 配置etcd数据库
vim /opt/etcd/cfg/etcd
#配置当前节点
#[member]
#当前节点名称
ETCD_NAME="etcd01"
#当前节点数据持久化存放位置
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
#集群通信监听地址, 当前节点ip
ETCD_LISTEN_PEER_URLS="https://192.168.255.130:2380"
#集群客户端访问监听地址, 当前节点ip
ETCD_LISTEN_CLIENT_URLS="https://192.168.255.130:2379"
#配置集群
#[Clustering]
#集群通告地址, 当前节点ip
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.255.130:2380"
#客户端通告地址, 当前节点ip
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.255.130:2379"
#集群ip
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.255.130:2380,etcd02=https://192.168.255.132:2380,etcd03=https://192.168.255.133:2380"
#集群tocken
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
#加入集群状态
ETCD_INITIAL_CLUSTER_STATE="new"```
5. 配置etcd数据库的systemctl管理, 每个节点都做
```YAML
vim /usr/lib/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=/opt/etcd/cfg/etcd
ExecStart=/opt/etcd/bin/etcd \
--name=${ETCD_NAME} \
--data-dir=${ETCD_DATA_DIR} \
--listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls=${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \
--advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS} \
--initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--initial-cluster=${ETCD_INITIAL_CLUSTER} \
--initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN} \
--initial-cluster-state=new \
--cert-file=/opt/etcd/ssl/server.pem \
--key-file=/opt/etcd/ssl/server-key.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem \
--peer-key-file=/opt/etcd/ssl/server-key.pem \
--trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/opt/etcd/ssl/ca.pem
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target```
6. 将cfssl证书文件拷贝到etcd集群主机
```YAML
cd /root/cert
cp ./ca*pem ./server*pem /opt/etcd/ssl
scp ./ca*pem ./server*pem 192.168.255.132:/opt/etcd/ssl
scp ./ca*pem ./server*pem 192.168.255.133:/opt/etcd/ssl```
7. 启动etcd数据库, 每个主机都操作
```YAML
systemctl daemon-reload
systemctl start etcd
systemctl enable etcd
systemctl status etcd -l```
8. 查看etcd集群状态
```Shell
#将etcdctl移动到可执行目录下
mv /opt/etcd/bin/etcdctl /usr/bin 
etcdctl --ca-file=/opt/etcd/ssl/ca.pem --cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.255.130:2379,https://192.168.255.132:2379,https://192.168.255.133:2379" cluster-health```
2.5.5 node节点安装docker
1. 配置docker的yum仓库
```Shell
yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo```
2. 安装docker
```Shell
yum -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin```
3. 启动docker, 并检查服务状态
```Shell
systemctl start docker 
systemctl enable docker
systemctl status docker -l
docker version```
2.5.6 node节点安装flanneld网络插件
1. 为node节点拷贝cfssl证书文件
```Shell
scp /root/cert/{ca*pem,server*pem} 192.168.255.132:/root
scp /root/cert/{ca*pem,server*pem} 192.168.255.133:/root ```
2. 将flanneld的配置, 写入etcd集群, 在etcd集群操作
```Thrift
etcdctl \
--ca-file=ca.pem --cert-file=server.pem --key-file=server-key.pem \
--endpoints="https://192.168.255.130:2379,https://192.168.255.132:2379,https://192.168.255.133:2379" \
set /coreos.com/network/config '{ "Network": "172.17.0.0/16", "Backend": {"Type": "vxlan"}}'```
3. node节点安装flanneld
```Shell
tar -zxvf ./flannel-v0.10.0-linux-amd64.tar.gz
mkdir -p /opt/kubernetes/bin
mv flanneld mk-docker-opts.sh /opt/kubernetes/bin```
4. node配置flanneld与etcd的连接
```Shell
mkdir -p /opt/kubernetes/cfg/
vim /opt/kubernetes/cfg/flanneld
#配置flanneld与etcd数据库集群的连接
FLANNEL_OPTIONS="--etcd-endpoints=https://192.168.255.130:2379,https://192.168.255.132:2379,https://192.168.255.133:2379 -etcd-cafile=/opt/etcd/ssl/ca.pem -etcd-certfile=/opt/etcd/ssl/server.pem -etcd-keyfile=/opt/etcd/ssl/server-key.pem"```
5. node配置flanneld的systemctl管理
```Shell
vim /usr/lib/systemd/system/flanneld.service
[Unit]
Description=Flanneld overlay address etcd agent
After=network-online.target network.target
Before=docker.service
[Service]
Type=notify
EnvironmentFile=/opt/kubernetes/cfg/flanneld
ExecStart=/opt/kubernetes/bin/flanneld --ip-masq $FLANNEL_OPTIONS
ExecStartPost=/opt/kubernetes/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/subnet.env
Restart=on-failure
[Install]
WantedBy=multi-user.target```
6. node配置docker启动指定子网段
```Shell
vim /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
EnvironmentFile=/run/flannel/subnet.env
ExecStart=/usr/bin/dockerd $DOCKER_NETWORK_OPTIONS
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target```
7. 由于flanneld需要cfssl证书, 确保node节点有pm文件
```Shell
mkdir -p /opt/etcd/ssl/
scp /root/cert/{ca*pem,server*pem} 192.168.255.132:/root
scp /root/cert/{ca*pem,server*pem} 192.168.255.133:/root ```
8. 启动docker和flanneld
```Shell
systemctl daemon-reload
systemctl start flanneld
systemctl enable flanneld
systemctl restart docker```
9. 检查ip信息, 测试不同node中docker0网卡之间的连通性
```Shell
#查看docker0与flanneld网卡配置信息
#确保单独的node中docker0与flanneld处于同一个网段
ps -ef | grep docker
ip a
ping 172.17.14.1```
2.5.7 master节点生成ca证书
1. 创建ca证书
```Shell
#由于master的api-server被访问时需要通过ca认证, 才能访问api-server
mkdir /opt/crt
vim /opt/crt/ca-config.json
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
vim /opt/crt/ca-csr.json
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}
cd /opt/crt
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -```
2. 生成api-server认证证书
```Shell
vim server-csr.json
{
    "CN": "kubernetes",
    "hosts": [
      #dns要使⽤的虚拟⽹络的⽹关
      "10.0.0.1",
      "127.0.0.1",
      #k8s集群地址
      "192.168.255.130",
      "192.168.255.132",
      "192.168.255.133",
      "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"
        }
    ]
}
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes server-csr.json | cfssljson -bare server```
3. 生成kube-proxy认证证书
```Shell
vim kube-proxy-csr.json
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing",
      "O": "k8s",
      "OU": "System"    }
  ]
}
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy```
2.5.8 master部署api-server组件
1. 拷贝ca证书到master
```Shell
cd /opt/crt
scp {ca*pem,server*pem} 192.168.255.130:/opt/kubernetes/ssl/```
2. 创建token文件, 为node连接master, 提供临时身份认证信息
```Shell
cd /opt/kubernetes/cfg/
#token字符串随意, 自己编写
#用户: kubelet-bootstrap
#uid:10001
#组:system:kubelet-bootstrap
vim ./token.csv
774c457d4dcf2eefe4920d7dbb6b0ddc,kubelet-bootstrap,10001,"system:kubelet-bootstrap"```
3. 安装api-server
```Shell
cd /root
mkdir -p /opt/kubernetes/{bin,cfg,ssl}
tar -zxvf kubernetes-server-linux-amd64.tar.gz
cd ./kubernetes/server/bin
cp kube-apiserver kube-scheduler kube-controller-manager kubectl /opt/kubernetes/bin```
4. 配置api-server
```Shell
cd /opt/kubernetes/cfg
vim ./kube-apiserver
#logtostderr=true启用日志
KUBE_APISERVER_OPTS="--logtostderr=true \
#日志等级
--v=4 \
#etcd集群ip
--etcd-servers=https://192.168.255.130:2379,https://192.168.255.132:2379,https://192.168.255.133:2379 \
#apiserver绑定的ip, masterip
--bind-address=192.168.255.130 \
#master对外端口
--secure-port=6443 \
#对外通告ip, master的ip
--advertise-address=192.168.255.130 \
--allow-privileged=true \
#service资源组件网段, 避免与pod和宿主机ip冲突
--service-cluster-ip-range=10.0.0.0/24 \
#集群资源管控插件
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \
--authorization-mode=RBAC,Node \
#node节点连接master, 启用token
--enable-bootstrap-token-auth \
#token文件路径
--token-auth-file=/opt/kubernetes/cfg/token.csv \
#Node服务的端口范围
--service-node-port-range=30000-50000 \
#API Server自身的TLS证书, 用于对外访问时使用
--tls-cert-file=/opt/kubernetes/ssl/server.pem \
--tls-private-key-file=/opt/kubernetes/ssl/server-key.pem \
#验证客户端证书的CA根证书
--client-ca-file=/opt/kubernetes/ssl/ca.pem \
#ServiceAccount的签名密钥
--service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \
#连接etcd集群的TLS证书
--etcd-cafile=/opt/etcd/ssl/ca.pem \
--etcd-certfile=/opt/etcd/ssl/server.pem \
--etcd-keyfile=/opt/etcd/ssl/server-key.pem"```
5. 配置api-server的systemctl
```Shell
cd /usr/lib/systemd/system
vim kube-apiserver.service
[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```
6. 启动apiserver
```Shell
systemctl daemon-reload
systemctl enable kube-apiserver
systemctl start kube-apiserver
systemctl status kube-apiserver -l```
2.5.6 master部署schduler组件
1. 创建schduler配置文件
```Shell
#由于前面完成了kube-scheduler复制到/opt/kubernetes/bin, 所以直接配置即可
vim  /opt/kubernetes/cfg/kube-scheduler
KUBE_SCHEDULER_OPTS="--logtostderr=true \
--v=4 \
--master=127.0.0.1:8080 \
#选举方式, 选出master节点中的schduler组件的boss
--leader-elect"```
2. 配置schduler的systemctl管理
```Shell
cd /usr/lib/systemd/system/
vim kube-scheduler.service
[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```
3. 启动schduler
```Shell
systemctl daemon-reload
systemctl enable kube-scheduler
systemctl start kube-scheduler
systemctl status kube-scheduler```
2.5.7 部署controller-manager组件
1. 创建controller-manager配置文件
```Shell
#由于前面完成了controller-manager复制到/opt/kubernetes/bin, 所以直接配置即可
cd /opt/kubernetes/cfg/
vim kube-controller-manager
KUBE_CONTROLLER_MANAGER_OPTS="--logtostderr=true \
--v=4 \
--master=127.0.0.1:8080 \
--leader-elect=true \
--address=127.0.0.1 \
--service-cluster-ip-range=10.0.0.0/24 \
--cluster-name=kubernetes \
--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"```
2. 配置controller-manager组件的systemctl管理
```Shell
cd /usr/lib/systemd/system/
vim kube-controller-manager.service
[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```
3. 启动controller-manager组件
```Shell
systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl start kube-controller-manager
systemctl status kube-controller-manager```
2.5.8 查看集群状态
```Shell
mv /opt/kubernetes/bin/kubectl /usr/bin
kubectl get cs```
注意: 
  1. k8s集群的高可用本质是保证api-server的高可用, 因为其他组件由--leader-elect来保证高可用, 对master节点的api-server采用轮询负载均衡即可
  2. ca证书作用: 验证apiserver身份, 防止kubelet连接到假apiserver
  3. token: 临时引导凭证, 用于新node节点首次加入集群的身份验证
  4. 申请ca证书: 用于取代token, 作为node节点的永久身份验证
  5. 新node节点认证: 当有新的node节点创建后, 该node节的kubelet会以kubeconfig(配置文件)形式携带ca认证信息与tocken, 向master的apiserver提交认证, master会验证身份的有效性, 之后master会将该node加入集群
  6. kubelet申请ca: node节点上的kubelet会以一个低权限用户自动向apiserver申请ca证书
2.5.9 master节点生成node需要认证的配置文件
1. 将node节点的认证用户绑定到集群
```Shell
#kubelet-bootstrap用户: 2.5.8步骤中创建的用户
kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper \
--user=kubelet-bootstrap```
2. master节点, 创建携带认证信息的config文件
```Shell
cd /opt/crt
#master的ip, 为提供node节点认证时的apiserver地址
KUBE_APISERVER="https://192.168.255.130:6443"
#2.5.8中创建的token
BOOTSTRAP_TOKEN=774c457d4dcf2eefe4920d7dbb6b0ddc```
3. 将集群相关参数, 记录在bootstrap.kubeconfig文件中, 为node节点的kubelet组件使用
  
```Shell
#集群参数
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=bootstrap.kubeconfig
#客户端认证参数
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
#设置默认上下文参数
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig```
4. 将参数记录在kube-proxy.kubeconfig文件中, 供node节点的kube-proxy组件使用
```Shell
kubectl config set-cluster kubernetes \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=kube-proxy.kubeconfig

kubectl config set-credentials kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=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

kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig```
5. 将文件发送给node节点使用
```Shell
scp ./*.kubeconfig 192.168.255.132:/opt/kubernetes/cfg/
scp ./*.kubeconfig 192.168.255.133:/opt/kubernetes/cfg/```
2.5.10 node节点部署kubelet组件
1. 将kubelet与kubeproxy文件拷贝到node节点
```Shell
scp /root/kubernetes/server/bin/{kubelet,kube-proxy} 192.168.255.132:/opt/kubernetes/bin/
scp /root/kubernetes/server/bin/{kubelet,kube-proxy} 192.168.255.133:/opt/kubernetes/bin/```
2. node节点, 拉取pause-amd64:3.0镜像
```Shell
docker pull docker.1ms.run/rancher/pause-amd64:3.0```
3. 创建kubelet配置文件
```Shell
cd /opt/kubernetes/cfg/
vim kubelet.config
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
#node节点的宿主机ip
address: 192.168.255.132
port: 10250
readOnlyPort: 10255
cgroupDriver: cgroupfs
clusterDNS: ["10.0.0.2"]
clusterDomain: cluster.local.
failSwapOn: false
authentication:
  anonymous:
    enabled: true
  webhook:
    enabled: false```
4. 创建kubelet启动配置文件
```Shell
vim /opt/kubernetes/cfg/kubelet
KUBELET_OPTS="--logtostderr=true \
--v=4 \
#node节点ip, 在查看集群时, 显示节点的宿主机ip
--hostname-override=192.168.255.132 \
#指定kubeconfig⽂件位置,会⾃动⽣成
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \
#指定创建的认证文件, 用于kubelet向spiserver认证
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \
#kubelet组件的配置文件存放路径
--config=/opt/kubernetes/cfg/kubelet.config \
#ca认证信息
--cert-dir=/opt/kubernetes/ssl \
#拉取的pause组件镜像
--pod-infra-container-image=docker.1ms.run/rancher/pause-amd64:3.0"```
5. 配置kubelet的systemctl管理
```Shell
vim /usr/lib/systemd/system/kubelet.service
[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```
6. 启动kubelet
```Shell
systemctl daemon-reload
systemctl enable kubelet
systemctl start kubelet
systemctl status kubelet -l```
7. master节点查看node节点的加入集群申请的状态
```Shell
#pending: 待批准
#denied: 拒绝
#approved: 已批准
kubectl get csr```
8. master节点手动批准, 将node加入集群
```Shell
#node加入集群需要master手动批准
kubectl certificate approve node-csr-CPQW8rg21xOCbeReUQ_zhOU3tY395WRiOqpmuUlVCvY
kubectl certificate approve node-csr-nEDTcF6nRJVM4PKbpvk2NLJexnPdAdXB42oM7rZVD94```
9. master查看节点状态
```Shell
kubectl get node```
2.5.11 node节点部署kubu-proxy组件
1. 创建kube-proxy的配置文件
```Shell
vim /opt/kubernetes/cfg/kube-proxy
KUBE_PROXY_OPTS="--logtostderr=true \
--v=4 \
#修改为每个node的ip
--hostname-override=192.168.255.132 \
--cluster-cidr=10.0.0.0/24 \
--kubeconfig=/opt/kubernetes/cfg/kube-proxy.kubeconfig"```
2. 配置kube-proxy的systemctl管理
```Shell
vim /usr/lib/systemd/system/kube-proxy.service
[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```
3. 启动kube-proxy
```Shell
systemctl daemon-reload
systemctl enable kube-proxy
systemctl start kube-proxy
 systemctl status kube-proxy -l```
4. master节点查看
```Shell
kubectl get node
#查看master组件信息
kubectl get cs```
2.5.12 在k8s集群中测试nginx容器服务
1. master节点安装docker
```Shell
yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl start docker 
systemctl enable docker
systemctl status docker -l
docker version```
2. 拉取nginx镜像
```Shell
docker pull docker.1ms.run/library/nginx:1.29.5-trixie-perl```
3. master启动nginx容器
```Shell
#nginx: 容器名称
#--image: 指定镜像
#--replicas: 启动数量
kubectl run nginx --image=docker.1ms.run/library/nginx:1.29.5-trixie-perl --replicas=3```
4. 查看pod状态
```Shell
kubectl get pod
#查看pod的详细信息
kubectl get pod -o wide```
5. 做容器中nginx的端口映射, 并查看端口映射关系
```Shell
kubectl expose deployment nginx --port=88 --target-port=80 --type=NodePort
kubectl get svc```
6. 测试访问
```Shell
curl http://192.168.255.132:44645```
2.6 kubeadm搭建k8s集群
2.6.1 环境
  192.168.255.130 master etcd: master
  192.168.255.132 node etcd: node1
  192.168.255.133 node etcd: node2
2.6.2 关闭防火墙与selinux
```YAML
systemctl disable firewalld
sed -ri 's/SELINUX=enforcing/SELINUX=disabled/' /etc/sysconfig/selinux
setenforce 0```
2.6.3 配置域名解析并修改主机名
```YAML
cat >> /etc/hosts << EOF
192.168.255.130 master etcd01
192.168.255.132 node1 etcd02
192.168.255.133 node2 etcd03
EOF
hostnamectl set-hostname master
su
hostnamectl set-hostname node1
su
hostnamectl set-hostname node2
su```
2.6.4 三台主机安装docker
```Shell
yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl start docker 
systemctl enable docker
systemctl status docker -l
docker version```
2.6.5 三台主机拉取镜像
```Shell
#拉取镜像脚本
vim img.sh
#!/bin/bash
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.19.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.19.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.19.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.19.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.7.0
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.13-0
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2
#转发脚本
scp img.sh 192.168.255.132:/root
scp img.sh 192.168.255.133:/root
#执行脚本
bash ./img.sh
#修改镜像标签为k8s官网, 因为kubead仅识别k8s官网镜像
#修改标签脚本
vim tag.sh
#!/bin/bash
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.19.1 k8s.gcr.io/kube-controller-manager:v1.19.1
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.19.1 k8s.gcr.io/kube-proxy:v1.19.1
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.19.1 k8s.gcr.io/kube-apiserver:v1.19.1
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.19.1 k8s.gcr.io/kube-scheduler:v1.19.1
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.7.0 k8s.gcr.io/coredns:1.7.0
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.13-0 k8s.gcr.io/etcd:3.4.13-0
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 k8s.gcr.io/pause:3.2
#转发脚本
scp tag.sh 192.168.255.132:/root
scp tag.sh 192.168.255.133:/root
#执行脚本
bash ./tag.sh
#检查镜像
docker images```
2.6.6 三台主机关闭swap分区
```Shell
#k8s的1.8版本后, 需要关闭swap分区
#一次关闭, 立即生效
swapoff -a
#将swap挂载注释, 重启生效
sed -i 's/.*swap.*/#&/' /etc/fstab
free -m```
2.6.7 三台主机yum安装kubelet, kubeadm, kubectl, ipvsadm
1. 配置yum仓库
```Shell
cat >> /etc/yum.repos.d/kubernetes.repo << EOF
[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
EOF```
2. 安装
```Shell
yum makecache
yum install -y kubelet-1.19.1-0.x86_64 kubeadm-1.19.1-0.x86_64 kubectl-1.19.1-0.x86_64 ipvsadm```
2.6.8 三台主机配置k8s负载均衡的网络与内存
1. 加载ipvs的内核模块
```Shell
#该文件开启启动自动加载, 是配置持久化
vim /etc/rc.local
#!/bin/bash
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack_ipv4
chmod a+x /etc/rc.local```
2. 启用rc-local服务
```Shell
systemctl enable rc-local
systemctl start rc-local
systemctl status rc-local```
3. 配置转发
```Shell
cat >> /etc/sysctl.d/k8s.conf << EOF    
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
vm.swappiness=0
EOF```
4. 重新加载配置
```Shell
sysctl --system```
5. 验证, 配置参数是否加载到内核
```Shell
lsmod | grep ip_vs```
2.6.9 三台主机配置kubelet
1. 获取docker的cgroups驱动
```Bash
DOCKER_CGROUPS=$(docker info  | grep  "Cgroup Driver" | awk '{print $3}')
echo $DOCKER_CGROUPS```
2. 配置kubelet的cgroup驱动与pause镜像
```Shell
cat >/etc/sysconfig/kubelet<<EOF
KUBELET_EXTRA_ARGS="--cgroup-driver=$DOCKER_CGROUPS --pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google_containers/pause-amd64:3.2"
EOF```
3. 启动kubelet
```Shell
systemctl daemon-reload
systemctl enable kubelet
systemctl start kubelet
#启动失败, 是因为ca还未配置, 下面会配置
systemctl status kubelet```
2.6.10 初始化master节点
1. 执行初始化, 会自动使用改了tag后的镜像
```Shell
kubeadm init --kubernetes-version=v1.19.1 --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.255.130 --ignore-preflight-errors=Swap```
2. 记录初始化成功后的操作提示与token, 并执行
```Bash
#可以将$HOME换成当前用户的家目录
mkdir -p /root/.kube
cp -i /etc/kubernetes/admin.conf /root/.kube/config
chown $(id -u):$(id -g) /root/.kube/config
#记录token
kubeadm join 192.168.255.130:6443 \
--token 7vz1f8.uqaucmc53eds7xov \
--discovery-token-ca-cert-hash sha256:16e5fc4751bea456016b627b7683e005c552f2f52cdf01d588241ac87e48bbc6```
3. 使用adm工具查看master节点
```Shell
kubectl get node```
2.6.11 master配置flannel网络
1. 查看kube-system命名空间的dns组件pod的状态
```Shell
#dns的组件pod显示未绑定, 下面配置, 将dns的pod启动
kubectl get pod -n kube-system```
2. 下载flannel的配置文件
```Shell
mkdir /root/flannel
cd /root/flannel
curl -O https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml```
3. 提前拉取镜像
```Shell
docker pull docker.1ms.run/rancher/mirrored-flannelcni-flannel:v0.18.1
docker pull docker.1ms.run/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0```
4. 修改flannel配置文件
```Shell
#将文件中所有命名空间的值改为kube-system
:1,210 s/namespace: kebu-flannel/namespace: kebu-system/g
#配置文件内容
---
kind: Namespace
apiVersion: v1
metadata:
  #修改为kebu-system
  name: kube-system
  labels:
    k8s-app: flannel
    pod-security.kubernetes.io/enforce: privileged
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: flannel
  name: flannel
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes/status
  verbs:
  - patch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: flannel
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  #修改为kube-system
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: flannel
  name: flannel
  #修改为kube-system
  namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  #修改为kube-system
  namespace: kube-system
  labels:
    tier: node
    k8s-app: flannel
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      #保证ip与初始化master时的--pod-network-cidr的值相同
      "Network": "10.244.0.0/16",
      "EnableNFTables": false,
      "Backend": {
        "Type": "vxlan"
      }
    }
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds
  namespace: kube-system
  labels:
    tier: node
    app: flannel
    k8s-app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                - linux
      #flannel调度pod时, 使用宿主机网络
      hostNetwork: true
      priorityClassName: system-node-critical
      #确保flannel能够调度所有节点
      tolerations:
      - operator: Exists
        effect: NoSchedule
      #配置
      - key: node.kubernetes.io/not-ready
        operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni-plugin
        #修改镜像为拉取的镜像
        image: docker.1ms.run/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0
        command:
        - cp
        args:
        - -f
        - /flannel
        - /opt/cni/bin/flannel
        volumeMounts:
        - name: cni-plugin
          mountPath: /opt/cni/bin
      - name: install-cni
        #修改镜像为拉取的镜像
        image: docker.1ms.run/rancher/mirrored-flannelcni-flannel:v0.18.1
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: docker.1ms.run/rancher/mirrored-flannelcni-flannel:v0.18.1
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        #指定flannel使用的宿主机网卡名称
        - --iface=ens33
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: EVENT_QUEUE_DEPTH
          value: "5000"
        - name: CONT_WHEN_CACHE_NOT_READY
          value: "false"
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
        - name: xtables-lock
          mountPath: /run/xtables.lock
      volumes:
      - name: run
        hostPath:
          path: /run/flannel
      - name: cni-plugin
        hostPath:
          path: /opt/cni/bin
      - name: cni
        hostPath:
          path: /etc/cni/net.d
      - name: flannel-cfg
        configMap:
          name: kube-flannel-cfg
      - name: xtables-lock
        hostPath:
          path: /run/xtables.lock
          type: FileOrCreate```
5. 执行配置文件, 创建flannel的pod
```Shell
kubectl apply -f ./kube-flannel.yml
#查看flannel的pod是否创建, 并验证dns的pod是否处于运行状态
kubectl get pod -n kube-system```
2.6.12 node节点加入集群
1. 所有节点实现pod的跨节点通信
```Shell
#所有节点执行
#临时有效
sysctl -w net.ipv4.ip_forward=1
#持久化
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/k8s.conf
#重新加载配置
sysctl --system
#验证
sysctl net.ipv4.ip_forward```
2. node操作, 将node加入master
```Shell
kubeadm join 192.168.255.130:6443 --token 7vz1f8.uqaucmc53eds7xov --discovery-token-ca-cert-hash sha256:16e5fc4751bea456016b627b7683e005c552f2f52cdf01d588241ac87e48bbc6```
第三章 k8s集群管理
3.1 pod操作
```Shell
#注意:
    # 不指定命名空间时, 默认查看的时default命名空间资源对象
    # 查看所有资源对象的详细信息, 也可以命令后加 -o wide
    # 查看所有命名空间的pod,加 --all-namespaces 参数
#查看默认命名空间的pod
kubectl get pod
#查看kube-system命名空间的pod
kubectl get pod -n kube-system
#查看指定pod: kube-flannel-ds-lbs24 的详细信息
kubectl decribe pod kube-flannel-ds-lbs24 -n kube-system
#删除pod: kube-flannel-ds-lbs24
kubectl delete pod kube-flannel-ds-lbs24 -n kube-system```
3.2 node操作
```Shell
#注意
    #对master节点重置后, 需要删除/var/lib/cni/ $HOME/.kube/config
#查看节点
kubectl get node
#查看指定节点: node1
kubectl get node node1
#查看节点详细信息
#主要查看node的event, 包括pod部署在了那个node, 镜像的拉取情况
kubectl describe node node1
#驱离节点node1上的pod到其他节点
#--delete-local-data: 强制删除本地的临时数据, 不加该参数, pod驱离后, 本地数据不会删除
#--force: 强制驱离该node, 由于有的节点进行了pvc, 不加参数无法驱离
#--ignore-daemon: 忽略daemonset的pod, 因为daemonset的pod驱逐后会立即重建
kubectl drain node1 --delete-local-data --force --ignore-daemonsets
#删除节点node1
kubectl delete node node1
#重置节点, 将节点恢复到未部署k8s的状态, 用于节点部署失败, 节点配置错误, 节点退出集群后
kubeadm reset```
3.3 token过期管理
```Shell
#注意:
    #token默认有效期为一天
#查看集群中的token
kubeadm  token list
#创建新的token
kubeadm token create
#查看ce证书的值
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
#node节点加入集群
kubeadm join master的ip:6443 --token kiyfhw.xiacqbch8o8fa8qj --discovery-token-ca-cert-hash sha256:5417eb1b68bd4e7a4c82aded83abc55ec91bd601e45734d6aba85de8b1ebb057
#也可使用下面命令,来加入集群, 一步即可 
kubeadm token create --print-join-command```
3.4 service管理
```Shell
#注意: 
    #也可以使用svc代替service
kubectl get service -n kube-system```
3.5 master节点信息
```Shell
#查看master宿主机的协议, ip, 端口, dns
kubectl cluster-info
#查看master的apiserver信息
kubectl api-versions```
第四章 k8s的资源对象
4.1 工作负载类
4.1.1 pod
4.1.1.1  定义与作用
1. 定义: pod是k8s最小的资源管理对象, 为容器提供运行的资源, 容器是pod的属性
注意:
  1. 每个pod的都有独立的网络资源(ip:port)
  2. k8s支持的配置文件类型: json与yml
  3. pod中, 若一个容器共享宿主机的命名空间, 那么该pod中的其他容器也会共享该宿主机的命名空间
4.1.1.2 pod中的容器
1. pause容器: 维护pod网络与存储, 是其他容器的父容器
2. 业务容器: 用户运行在pod中的业务
3. 初始化容器: 在pod启动前, 对pod进行初始化
4.1.1.3 pod中共享资源组件
1. 网络资源: 容器共享pod的ip与port端口空间
2. 存储资源: 通过挂载相同的卷, 来实现容器之间的文件共享
3. 进程与通信资源: 容器之间可查看与操作彼此进程
4.1.1.4 pod与容器的关系
4.1.1.5 pod的节点调度
1. 将pod创建到用户指定的节点
注意:
  1. 不指定pod调度方式的情况下, k8s会评估node的资源, 会将pod部署在可用资源最多的node 
  2. nodeselector: 该pod指定在含有指定标签的主机运行, 调度到其他节点会运行失败
  3. 主机别名: 直接修改pod中容器的文件, 重建pod后, 修改内容会被覆盖, 而这种方式, 在pod重建后, 修改内容不会被覆盖
4.1.1.5.1 namenode(指定节点名称)
```Shell
cd /root/pod
#通过nodename定义pod的调度节点
vim ./nodename.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: kubesystem   #指定pod的命名空间
  name: nginx
  labels:
    app: nginx
spec:
  nodeName: node1  #指定pod在node节点上创建并运行
  containers:
    - image: docker.1ms.run/library/nginx:mainline-trixie
      name: nginx  #容器名称
      ports:
        - containerPort: 80
#创建pod
kubectl apply -f ./nodename.yml
#查看pod的运行节点
kubectl get pod nginx -n kube-system -o wide
#测试
curl http://10.244.1.2 ```
4.1.1.5.2 nodeSelector(指定节点唯一性表示)
```Shell
#查看指定节点的标签(labels)
kubectl describe node node1
cd /root/pod
vim ./nodeselector.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: nginx
  labels:
    app: nginx
spec:
  nodeSelector:
    kubernetes.io/hostname: node1
  containers:
    - name: nginx
      image: docker.1ms.run/library/nginx:mainline-trixie
      ports:
        - containerPort: 80
#创建pod
kubectl apply -f ./nodeselector.yml
#查看pod
kubectl get pod -o wide```
4.1.1.5.3 主机别名(hosts文件)
```YAML
cd /root/home
vim tomcat.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: tomcat
  labels:
    app: tomcat
spec:
  hostAliases:
  - ip: "192.168.255.132"   #给哪个ip做解析。实验环境下这个ip⾃定义的    hostnames:
    - "foo.remote"    #解析的名字。⽤引号引起来可以写多个
    - "bar.remote"
  containers:
    - name: test-tomcat
      image: docker.1ms.run/library/tomcat:8
      ports:
        - containerPort: 8080
#创建pod
kubectl apply -f ./tomcat.yml
#进入pod的容器
kubectl exec -it tomcat /bin/bash
#查看文件
cat /etc/hosts```
4.1.1.6 pod的状态
1. pending: pod已经被k8s接受, 但容器还未启动
2. running: pod已经绑定到节点, 有容器成功运行
3. suceeded: 所有容器正常运行完毕
4. failed: pod中至少有一个容器异常
5. unknow: 无法获取pod, 节点之间通信失败
4.1.1.6.1 lifecycle
```Shell
cd /root/pod
vim life.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: nginx
spec:
  containers:
    - name: nginx
      image: docker.1ms.run/library/nginx:mainline-trixie
      lifecycle:
        postStart:   #容器启动之后, 执行下面命令
          exec:
            command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
        preStop:   #容器关闭之前执行的命令
          exec:
            command: ["/usr/sbin/nginx","-s","quit"]
#创建pod
kubectl apply -f ./life.yml
#查看pod
kubectl get pod -o wide
#切换到对应的node上
ssh root@192.168.255.132
#查看nginx进程
docker ps
docker exec -it  k8s_nginx_nginx_default_c5b7a223-e229-44e1-a6d2-e14282fa0b99_0 /bin/bash
cat /usr/share/message```
4.1.1.7 创建第一个pod
```Shell
mkdir /root/pod
cd /root/pod
#定义pod
vim ./pod.yml
---
apiVersion: v1
kind: Pod
metadata:  #定义pod基本属性
  name: website-nginx  #pod名称
  labels:
    app: website-nginx  #pod标签
spec: #pod中依赖其他属性
  containers: #定义pod中的容器
  - name: nginx-web  #业务容器名称
    image: docker.1ms.run/ngxin:latest  #nginx-web容器的镜像
    ports: #该容器运行的端口
      - containerPort: 80
#创建pod
kubectl apply -f ./pod.yml
#查看pod
kubectl get pod
#查看pod详细信息, 其中event反应pod情况
kubectl describe pod website-nginx
kubectl describe pod website-nginx -o yaml -n default
#查看pod调度到了那个node, 与pod分配的ip
kubectl get pod -o wide
#测试访问pod中的容器
curl pod的ip
#进入pod中
kubectl exec -it website-nginx /bin/bash
#删除pod
kubectl delete -f ./pod.yml
kubectl delete pod website-nginx -n default```
注意:
  1. create: create创建pod后, 若需要修改yml后新开pod, 需要指定yml删除pod之后才能创建
  2. apply: aaply创建的pod, 可以直接对yml进行修改, 之后apply需要的pod即可, 不用删除原有pod
  3. 除了yml创建资源对向, k8s还支持 kubectl run 与 kubectl expose
4.1.1.8 pod中容器镜像的拉取策略
1. always: 每次创建pod, 不论镜像在本地是否存在, 都会重新拉取
2. ifnotpersent: 若镜像存在, 使用本地镜像; 若镜像不存在, 才会拉取镜像
3. never: 仅使用本地镜像
注意:
latest镜像: 在不指定镜像拉取策略时, 默认采用always策略
其他镜像: 在不指定镜像拉取策略时, 默认采用ifnotpersent
4.1.1.8.1 always
```YAML
cd /root/pod
vim ./always.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node1
  containers:
    - name: nginx
      image: docker.1ms.run/nginx:latest
      imagePullPolicy: Always  #定义镜像拉取策略为always```
4.1.1.8.2 ifnotpersent
```YAML
cd /root/pod
vim ./ifnotpersent.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node1
  containers:
    - name: nginx
      image: docker.1ms.run/nginx:latest
      imagePullPolicy: IfNotPersent  #定义镜像拉取策略为ifnotpersent```
4.1.1.8.3 never
```YAML
cd /root/pod
vim ./always.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node1
  containers:
    - name: nginx
      image: docker.1ms.run/nginx:latest
      imagePullPolicy: Never  #定义镜像拉取策略为Never```
4.1.1.9 pod的资源限制
1. cpu资源限制: 通过limit与request限制pod的cpu资源
2. 内存资源限制: 通过limit与request限制pod的内存资源
注意:
  1. limit: 限制pod资源的上限, 可以超过request, 但不能超过limit, 决定pod运行时占用资源的上限
  2. request: 创建容器时预留的资源, 不是容器的运行的使用资源, 决定pod的调度到哪个节点部署
  3. limit应该大于或等于request
  4. pod是集群的进程
  5. 若为容器仅设置limit, k8s会自动为该容器分配与limit相等的request值, 
  6. 若未设置limit与request, 那么k8s会自动分配
  7. cpu资源限制可以指定小数, 0.5: 表示半颗cpu
  8. 若一个pod中, 有两个容器, 那么该pod的资源限制就为, 两个容器资源的和
```Shell
cd /root/pod
vim ./source.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: source
  labels:
    app: nginx
spec:
  containers:
    - name: nginx1
      image: docker.1ms.run/library/nginx:mainline-trixie
      env:   #定定义环境变量
        - name: WEB1_ROOT_PASSWORD  #环境变量名称
          value: "password1"  #环境变量的值
      resources:  #定义资源限制
        requests:  #定义request资源限制
          memory: "64Mi"  #request的内存
          cpu: "250m"  #request的cpu
        limits:  #定义limit资源限制
          memory: "128Mi"  #limit的内存
          cpu: "500m"  #limit的cpu
      ports:
        - containerPort: 80
    - name: nginx2
      image: docker.1ms.run/library/nginx:mainline-trixie
      env:
        - name: WEB2_ROOT_PASSWORD
          value: "password2"
      resources:
        requests:
          memory: "64Mi"
          cpu: "250m"
        limits:
          memory: "128Mi"
          cpu: "500m"
       command:   #定义容器启动后执行的命令
        - /bin/sh
        - -c
        - |
          cat > /etc/nginx/conf.d/default.conf << EOF
          server {
              listen       81;  # 监听81端口,避免与nginx1冲突
              server_name  localhost;
              root   /usr/share/nginx/html;
              index  index.html index.htm;
              error_page   500 502 503 504  /50x.html;
              location = /50x.html {
                  root   /usr/share/nginx/html;
              }
          }
          EOF
          nginx -g 'daemon off;'
      ports:
        - containerPort: 81
#创建pod
kubectl apply -f ./source.yml
#```
4.1.1.10 命名空间共享
4.1.1.10.1 pod中的容器之间共享
  
```Shell
cd /cd /root/ns
vim boxshare.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: website
  labels:
    app: website
spec:
  shareProcessNamespace: true  #两个容器之间互相共享进程名称空间
  containers:
    - name: test-web
      image: docker.1ms.run/library/nginx
      ports:
        - containerPort: 80
    - name: busybos
      image: docker.1ms.run/library/busybox
      stdin: true   #可以在标准输入中输入
      tty: true   #开启容器的标准输入
#创建pod
kubectl apply -f ./boxshare.yml
#查看pod在哪个node上运行
kubectl get pod -o wide
#在对应的node上, 使用docker进入容器
docker ps
docker exec -it 12cd457 /bin/sh
#验证是否可以看到nginx的进程
ps```
4.1.1.10.2 pod中的容器与宿主机共享
```YAML
cd /cd /root/ns
vim boxsharehost.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: website
  labels:
    app: website
spec:
  hostNetwork: true  #共享宿主机⽹络
  hostIPC: true  #共享ipc通信
  hostPID: true  #共享宿主机的pid
  containers:
    - name: test-web
      image: docker.1ms.run/library/nginx
      ports:
        - containerPort: 80
    - name: busybos
      image: daocloud.io/library/busybox
      stdin: true
      tty: true
#创建pod
kubectl apply -f ./boxsharehost.yml
#查看pod在哪个node上运行
kubectl get pod -o wide
#在对应的node上, 使用docker进入容器
docker ps
docker exec -it 12cd457 /bin/sh
#验证是否可以看到宿主机的进程
ps```
4.1.2 deployment
4.1.2.1 定义
1. 管理无状态pod, 实现pod的全生命周期管理与更新回滚等功能
注意:
  1. 控制器模式: 是一种资源对象(deployment)管理另一中资源对象(pod)
  2. 删除deployment后pod自动也会删除
4.1.2.2 功能
1. 维持pod副本数, 挂掉自动重建
2. 滚动更新: 不停机更新引用
3. 版本回滚
4. 弹性扩缩容
4.1.2.3 pod创建的流程
1. 用户通过kubectl创建depolyment
2. depolyment创建replicaset
3. replicaset创建pod
注意:
  1. deployment: 负责更新策略, 版本记录与回滚
  2. replicaset: 负责维持pod数量, 维持pod的扩缩容
4.1.2.4 应用deployment
```YAML
cd /root/dm
#定义deployment
vim ./dm.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: default
  name: nginx-dm
spec:  #定义dm属性
  selector:  #dm的选择器, 用于指定pod
    matchLabels:
      app: nginx
  replicas: 2  #定义pod数量为2个
  template:  #定义dm的模板(pod)
    metadata:
      labels:
        app: nginx  #(pod的标签)
    spec: #定义pod属性
      containers:
      - name: nginx
        image: docker.1ms.run/library/nginx
        ports:
        - containerPort: 80
        volumeMounts:  #引用卷
        - mountPath: "/usr/share/nginx/html"
          name: nginx-vol
      volumes: #定义卷
      - name: nginx-vol
        emptyDir: {}  #卷为临时目录, pod删除后数据丢失
kubectl apply -f ./dm.yml
kubectl get deployment -n default -o wide
kubectl describe deployment nginx-dm -n default
#查看pod
#-l表示指定标签
kubectl get pod -l app=nginx
#删除deployment
kubectl delete deployment nginx-dm```
4.1.3 daemonset
4.1.3.1 定义
1. 在集群中的每节点上都运行一个pod副本
注意:
  1. 当有新的节点加入后, 那么该节点就会分配一个daemonset创建的pod
  2. 当有节点删除时, daemonset会回收该节点上的pod
  3. 不能定义pod副本数量, 会根据集群node数量, 决定pod数量
  4. daemonset模式下, 可以使用hostPort, 因为pod不会被调度到其他节点
  5. hostPort: 可以通过宿主机ip+hostPort, 来实现对pod的访问
4.1.3.2 应用daemonset
```Shell
cd /root/ds
#定义daemonset
vim ./ds.yml
---
apiVersion: apps/v1
kind: DaemonSet
metadata:   #定义daemonset基本信息
  namespace: default
  name: nginx-ds
  labels:
    app: nginx-ds
spec:   #定义daemonset的属性
  selector:   #定义选择器, 选择标签为 app: nginx 的pod
    matchLabels:
      app: nginx
  template:  #定义pod
    metadata:  #pod基本信息
      namespace: default
      labels:
        app: nginx
    spec:  #定义pod其他信息
      containers:
      - name: nginx
        image: docker.1ms.run/library/nginx
        ports:
        - name: nginx-port
          containerPort: 80
          hostPort: 8888   #让宿主机8888端口对应容器80端口
          protocol: TCP   #通过tcp协议建立连接(四层)
kubectl apply -f ./ds.yml
kubectl get daemonset -n default
kubectl get pod -l app=nginx -n default -o wide
curl http://192.168.255.132:8888
curl http://192.168.255.133:8888```
4.1.4 statefulset
4.1.4.1 定义
1. 管理有状态的pod,  为每个pod赋予固定身份和专属的持久化
注意:
  1. statefulset类型的pod重建后, 固定身份不变, 存储不变
4.1.4.2 特点
1. 固定且唯一的身份: 重建后pod名称, dns域名解析不变
2. 专属的持久存储: 通过pvc/pv与自动绑定, 为每个pod分配独有的存储卷, pod重建后, 新pod会自动挂载原来的卷, 确保pod重建数据不丢失
3. 有序性: pod的创建与回收是有序的, 只有前一个pod创建或回收成功, 才会创建或回收一下个pod
4. 扩缩容保留身份: 会在原有的基础上有序扩缩, 不会打乱pod身份
4.1.4.3 应用statefulset
2. node安装nfs
```Shell
yum -y install nfs-utils rpcbind
systemctl start rpcbind
systemctl enable rpcbind```
3. master部署nfs, 支撑pod数据持久化
```Shell
yum -y install nfs-utils rpcbind
#pos数据持久化目录
mkdir /opt/container_data
chmod -R 777 /opt/container_data
#配置客户端对container_data目录的读写权限
echo "/opt/container_data *(rw,no_root_squash,no_all_squash,sync)"  >> /etc/exports
#启动服务
systemctl start rpcbind nfs
systemctl enable rpcbind nfs```
4. 定义storage, 支持动态存储
```Shell
cd /root/ss
vim ./storage.yml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs #绑定nfs的存储插件, 指定该插件负责pv的动态创建
kubectl apply -f ./storage.yml
kubectl get storageclass```
5. 为storage提供授权, 因为storage自动创建pv需要向apiserver申请
```Shell
cd /root/ss
vim ./rbac.yml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]  #k8s核心资源组
    resources: ["persistentvolumes"]  #pv
    verbs: ["get","list","watch","create","delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]  #pvc
    verbs: ["get","list","watch","update"]
  - apiGroups: ["storage.k8s.io"]  #存储专属 API 组
    resources: ["storageclasses"]   #sc
    verbs: ["get","list","watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list","watch","create","update","patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f ./rbac.yml```
6. 部署自动创建pv的任务
```Shell
cd /root/ss
vim ./dmnfs.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  selector:
    matchLabels:
      app: nfs-client-provisioner
  replicas: 1
  strategy:  #pod更新策略
    type: Recreate  #先删旧pod, 在创建pod
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image:  docker.1ms.run/lizhenliang/nfs-client-provisioner:v2.0.0
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.255.130 #nfs服务器宿主机ip
            - name: NFS_PATH
              value: /opt/container_data
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.255.130  #nfs服务器宿主机ip
            path: /opt/container_data
kubectl apply -f ./dmnfs.yml```
7. 创建statefulset
```YAML
cd /root/ss
vim ./ss.yml
#定义service, 用于通过宿主机ip+80端口, 访问pod内的80端口
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None  #不为该service配置集群ip, 用于指定pod访问
  selector:
    app: nginx   #让该service为标签为app:nginx的pod服务
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"  #引用service
  replicas: 2  #两个pod
  selector:
    matchLabels:
      app: nginx  #指向pod
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: docker.1ms.run/library/nginx
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:  #statefulset的特有卷模板(pvc模板), 为每个pod自动生成持久化的卷
  - metadata:
      name: www
    spec:
      accessModes: ["ReadWriteOnce"]  #单个节点上的pod可以对该卷进行读写
      storageClassName: "managed-nfs-storage"  #关联storageclass
      resources:
        requests:
          storage: 1Gi  #每个pod可使用的卷的大小
kubectl apply -f ./ss.yml
#验证是否有序创建
kubectl get pod
#验证数据持久化, 双向的
kubectl exec -it web-0 /bin/bash
cd /usr/share/nginx/html
echo "test1" > index.html
cat /opt/container_data/default-www-web-
0-pvc-7f0e1150-50c5-4fa3-9aab-a9ad7d9da009/index.html
#验证持久化
kubectl delete pod web-0```
4.2 网络服务类
4.2.1 service
4.2.1.1 定义
1. 为具有相同功能的一组pod提供固定访问入口, 负载均衡以及服务发现, 解决了pod ip的动态变化, 以及多副本流量调度的问题
4.2.1.2 工作原理
1. apiserver会通过label匹配pod, 并与service进行绑定, 以endpoint的形式存储; 同时kube-proxy会监听apiserver上的service与endpoint的变化, 来更新node上的service与endpoint的绑定关系, 并保存到ipvs中
2. 当客户端发起对service的访问后, 会先通过域名解析, 将域名转换为service的ip, 之后会在ipvs中根据该ip来匹配endpoint
3. 当匹配到endpoint后, ipvs会通过负载均衡算法, 来将请求转发给pod
注意:
  1. service(ipvs)提供的负载均衡是四层ip网络层的负载均衡
4.2.1.3 分类
1. clusterIP: 用于集群内部的互相访问, 提供固定ip
2. nodePort: 应用的宿主机ip与端口, 来对外提供服务, 利用clusterip生成的虚拟ip, 来实现对其他内部组件的访问
3. loadBalancer: 在nodeport的基础上, 提供负载均衡的ip, 实现分流
4. ExternalName: 引入集群外部的服务, 并未外部服务应用别名, 来实现对外部服务的访问
注意:
  1. k8s默认的service的类型为clusterIP
  2. nodeport模式的宿主机端口号范围: 30000-32767
4.2.1.4 clusterIP
1. 三台主机安装iptables
  
```Shell
yum install -y iptables iptables-service```
2. 利用deployment创建pod
```Shell
cd /root/svc
vim /pod.yml
---
apiVersion: apps/v1
kind: Deployment  #创建pep
metadata:
  name: nginx-dev
  labels:
    name: nginx-dev  #dep标签
spec:
  selector:  #dep选择标签为name:nginx-web的pod, 并创建2个
    matchLabels:
      name: nginx-web
  replicas: 2
  template:   #定义pod
    metadata:
      labels:
        name: nginx-web  #pod标签名
    spec:
      containers:
      - name: nginx  #容器名称
        image: docker.1ms.run/library/nginx
        ports:
        - containerPort: 80  #容器端口
kubectl apply -f ./pod.yml```
3. 创建clusterip类型的service
```Shell
cd /root/svc
vim ./svc.yml
---
apiVersion: v1
kind: Service
metadata:
  name: svc-dep-nginx
spec:
  type: ClusterIP  #service类型
  selector:
    name: nginx-web  #该svc与标签为name:nginx-web的pod绑定
  ports:
    - protocol: TCP  #使用TCP连接处理请求
      port: 8080    #svc的暴露端口
      targetPort: 80  #该svc的8080为80端口的name:nginx-web的pod进行绑定
 kubectl apply -f ./svc.yml```
4. 创建访问类型的pod
```Shell
cd /root/svc
vim ./test.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: test-svc
    image: docker.1ms.run/library/nginx
    ports:
      - containerPort: 80
kubectl apply -f ./test.yml```
5. 测试访问
```Shell
#查看serviceip
kubectl get service
kubectl exec -it web /bin/bash
curl http://serviceip:8080```
4.2.1.5 nodeport
1. 三台主机安装iptables
```Shell
yum install -y iptables iptables-service```
2. 利用deployment创建pod
```Shell
cd /root/svc
vim /pod.yml
---
apiVersion: apps/v1
kind: Deployment  #创建pep
metadata:
  name: nginx-dep
  labels:
    name: nginx-dep  #dep标签
spec:
  selector:  #dep选择标签为name:nginx-web的pod, 并创建2个
    matchLabels:
      name: nginx-web
  replicas: 2
  template:   #定义pod
    metadata:
      labels:
        name: nginx-web  #pod标签名
    spec:
      containers:
      - name: nginx  #容器名称
        image: docker.1ms.run/library/nginx
        ports:
        - containerPort: 80  #容器端口
kubectl apply -f ./pod.yml```
3. 创建clusterip类型的service
```Shell
cd /root/svc
vim ./np.yml
---
apiVersion: v1
kind: Service
metadata:
  name: svc-np-nginx
spec:
  type: NodePort  #service类型
  selector:
    name: nginx-web  #该svc与标签为name:nginx-web的pod绑定
  ports:
    - protocol: TCP  #使用TCP连接处理请求
      nodePort: 30001  #宿主机上暴露端口对外服务
      port: 8080    #svc的暴露端口
      targetPort: 80  #该svc的8080为80端口的name:nginx-web的pod进行绑定
 kubectl apply -f ./np.yml```
4. 测试
```Shell
 curl http://宿主机ip:30001```
4.2.2 ingress
4.2.2.1 定义
1. 定义请求根据url的转发规则
注意:
  1. 是七层反向代理负载均衡
4.2.2.2 组成
1. nginx反向代理负载均衡:  负责隐藏后端资源架构, 以及流量的分发
2. ingress控制器: 实时向apiserver获取pod与service的变化, 并结合ingress定义的规则, 动态更新nginx负载均衡器
3. ingress: 定义域名与service的绑定关系
4.2.2.3 暴露方式
1. nodeport: 提供宿主机ip+port来被客户进行访问, 并通过service转发给ingress
2. hostnetwork: 提供宿主机ip+port来被客户进行访问, 不用经过service的转发, 直接交给ingress
4.2.2.4 部署ingress(hostNetwork方式)
1. 下载ingress安装包
```Shell
cd /mnt
wget https://github.com/kubernetes/ingress-nginx/archive/nginx-0.30.0.tar.gz
tar xzvf nginx-0.30.0.tar.gz
cd ingress-nginx-nginx-0.30.0/deploy/static/```
2. 修改mandatory.yaml文件
```YAML
apiVersion: apps/v1
kind: DaemonSet  #将原来的Deployment修改为DaemonSet
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  #replicas: 1 #将这⾥注释
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      hostNetwork: true  #添加此配置,共享宿主机⽹络
#      nodeSelector:
#        custom/ingress-controller-ready: "true"  #添加此配置
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0 #提前将镜像下载下来
          args:
            - /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io
          securityContext:
            allowPrivilegeEscalation: true
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE    # www-data -> 101
            runAsUser: 101
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
          livenessProbe:
            failureThreshold: 3 
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          lifecycle:
            preStop:
              exec:
                command:
                  - /wait-shutdown```
3. 部署ingress
```Shell
kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f rbac.yaml```
4. node节点拉取镜像
```Shell
docker pull quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0```
5. 创建ingress-contrallor
```Shell
kubectl apply -f /root/mandatory.yaml```
4.2.2.5 hostNetwork:true
1. 创建pod与service
```YAML
cd /root/in
vim ./my-apache.yaml
---
apiVersion: apps/v1
kind: Deployment   #定义dep
metadata:
  name: dep
spec:
  selector:
    matchLabels:
      run: my-apache   #选择标签为run: my-apache的pod, 进行管理
  replicas: 2  #该pod有2个
  template:  #定义[pod]
    metadata:
      labels:
        run: my-apache   #定义pod标签
    spec:
      containers:
      - name: http
        image: daocloud.io/library/httpd:2.4     
        ports:
        - containerPort: 80  #pod内容器端口
---
apiVersion: v1
kind: Service  #定义service
metadata:
  name: svc
    labels:
      name: svc
spec:
  ports:
  - port: 80  #srevice对外暴露的端口
    targetPort: 80   #servic接收到请求, 转发给容器的80端口
  selector:
    run: my-apache    #该svc与标签为 run: my-apache的pod进行绑定
kubectl apply -f my-apache.yaml```
2. 配置ingerss的转发规则为hostWork:true
```Shell
cd /root/in
vim ./ingress-test.yaml
---
apiVersion: networking.k8s.io/v1
kind: Ingress   #定义ingress
metadata:
  name: test-ingress
  namespace: default
  annotations:   #将用户请求原url改为/, 并根据下面的rule将请求转发service
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:  #定义转发规则
  - host: www.ingress.com  #匹配用户访问域名是否为:www.ingress.com
    http:
      paths:
      - path: /  #指定访问的路径
        pathType: Prefix  #路径配置规则为前缀匹配
        backend:   #定义转发后端的服务
          service:  #定义转发的service
            name: svc   #service的名称
            port:
              number: 80 #service端口号,由于Ingress控制器开启了hostNetwork: true。这⾥必须设置80
kubectl apply -f ingress-test.yaml
#配置hosts文件, 并测试访问
http://www.ingress.com```
4.2.2.6 nodePort
1. 修改mandatory.yaml文件
```Shell
cat mandatory.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: udp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
    - apiGroups:
      - "extensions"      - "networking.k8s.io"    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
    - apiGroups:
        - "extensions"
        - "networking.k8s.io"    
      resources:
        - ingresses/status
      verbs:
        - update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: nginx-ingress-role
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
    resourceNames:
      - "ingress-controller-leader-nginx"
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - get
---
apiVersion: rbac.authorization.k8s.io/v1beta1kind: RoleBinding
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccoun
    namespace: ingress-nginx```
2. 配置pod与service
```YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-apache
spec:
  selector:
    matchLabels:
      run: my-apache
 replicas: 2
 template:
   metadata:
     labels:
       run: my-apache
   spec:
     containers:
     - name: my-apache
       image: daocloud.io/library/httpd:2.4
       ports:
       - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-apache
  labels:
    run: my-apache
spec:
  type: NodePort #指定service的type为nodeport
  ports:
  - port: 80  #svc对外端口
    targetPort: 80   #容器对外端口
    nodePort: 30002  #指定宿主机上的对外端口
 selector:  #绑定svc
  run: my-apache```
3. 配置转发规则
```YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:  #定义转发规则
  - host: www.ingress.com
    http:
      paths:
      - path: /  #指定访问的路径
        pathType: Prefix  #定义路径的类型
        backend:   #定义转发后端的服务
          service:  #定义转发的service
            name: my-apache
            port:
              number: 80  #这个跟clusetrIP端⼝保持⼀致;这⾥有点模糊。
 - host: www.youngfit.com
   http:
     paths:
     - path: /
       pathType: Prefix
       backend:
         service:
           name: my-nginx
           port:
             number: 80```
4.3 存储类
4.3.1 特殊卷
4.3.1.1 secret
1. secret用来存放小片的敏感数据(密码, token, 秘钥), 增强敏感数据额安全性
注意:
  1. k8s集群有默认的secret, 用户也可以创建自己的secret
  2. pod需要引用, 才能使用secret
  3. secret是区分命名空间的
  4. volume是指为pod中的容器提供预定义的数据
  5. secret, config, downward api的环境变量形式无法实现, 他们更新后, 容器内也更新, 所以推荐使用卷挂载
4.3.1.1.1 命令方式创建secret
```Shell
#注意:
    #secret默认的数据类型是opaque也就是map, 他的值会采用base64格式存储
mkdir /root/secret
cd /root/secret
echo "zs" > user.txt
echo "123456" > pass.txt
#创建secret
#db-user-pass: secret的名称
kubectl create secret generic db-user-pass --from-file=./user.txt --from-file=./pass.txt
#验证是否创建
kubectl get secret -n default
#查看详细信息
kubectl describe secret db-user-pass
#查看详细信息, 内容为base64加密后的
kubectl get secret db-user-pass -o yaml
#对加密的内容解码
echo "加密字符串" | base64 --decode```
4.3.1.1.2 yml方式创建secret
```Shell
#先对信息进行加密
echo "zs" | base64
echo "123456" | base64
#定义secret
cd /root/secret
vim /sc.yml
---
apiVersion: v1
kinf: Secret   #资源对象类型为secret
metadata:
  namespace: default   #在默认命名空间下创建
  name: mysecret   #secret对象的名称
type: Opaque   #数据存储类型
data:   #声明存储的数据
  user: enMK   #存储zs编码的字符串
  passwd: MTIzNDU2Cg==  #存储123456编码后的字符串
#创建secret
kubectl apply -f ./sc.yml
#验证
kubectl get secret
#查看信息
kubectl get secret mysecret -o yaml```
4.3.1.1.3 卷挂载引用secret
```Shell
#注意
  #文件中的保存的内容为解码后的内容
  #文件名称与secret定义的变量名称相同
  #若pod中的多个容器都需要使用该secret, 那么每个容器的定义都需要声明volumemounts, 来定义挂载的位置
  #volumemounts挂载方式的secret, 会随secret的更新而更新, 但更新时间不确定
  #会将secret中所有的数据挂载到容器
cd /root/secret
vim use1.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: use-sc
spec:
  containers:
    - name: test
      image: docker.1ms.run/library/nginx
      volumeMounts:  #声明需要挂载的卷
        - name: foo  #卷名称, 与volums中定义的卷名称一致
          mountPath: "/etc/foo"  #挂载到容器的foo目录
          readOnly: true   #对卷只有读的权限
  volumes:  #定义卷
    - name: foo  #创建的卷名称
      secret:  #卷中引用secret
        secretName: mysecret  #引用secret的名称
#创建pod
kubectl apply -f ./use1.yml
#进入pod
kubectl exec -it use-sc /bin/bash
#查看容器中挂载的卷
cd /etc/foo
ls
#查看卷中文件
cat passwd
cat user```
4.3.1.1.4 映射secret到指定路径引用
```Shell
#注意:
  #将secret中指定的数据挂载到容器
cd /root/secret
vim ./use2.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: use-sc-key
spec:
  containers:
    - name: test
      image: docker.1ms.run/library/nginx
      volumeMounts:
        - name: foo
          mountPath: "/etc/foo"
          readOnly: true
  volumes:
    - name: foo
      secret:
        secretName: mysecret
        items:  #定义可使用的值
          - key: username  #应用secret的username
            path: uu/user.txt  #存方在/etc/foouu/user.txt中
#创建pod
kubectl apply -f ./use2.yml
#进入pod
kubectl exec -it use-sc-key /bin/bash
#查看容器中挂载的卷
cd /etc/foo/uu
ls
#查看卷中文件
cat user.txt```
4.3.1.1.5 环境变量方式引用secret
```Shell
#注意:
  #环境变量方式引用后, secret更新, pod不会更新
cd /root/secret
vim ./use3.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: use-sc-env
spec:
  containers:
    - name: test
      image: docker.1ms.run/library/nginx
      env: #声明环境变量
        - name: MYSQL_ROOT_PASSWORD #定义环境变量MYSQL_ROOT_PASSWORD
          vauleFrom: #声明值的来源
            secretKeyRef:  #调用secret的值
              name: mysecret   #在mysecret的secret中取值
              key: username  #值
kubectl apply -f ./use3.yml
kubectl exec -it use-sc-env /bin/bash
echo "$MYSQL_ROOT_PASSWORD"```
4.3.1.2 configmap
1. 定义: 用来存储配置文件, 来应用在k8s的资源对象中
注意:
  1. 与secret的区别: 存储无需加密的数据
  2. configmap是区分命名空间的
4.3.1.2.1 命令行创建
```Shell
#--from-literal: 在创建configmap的时候指定参数
kubectl create configmap test --from-literal=user=zs --from-literal=pass=123456
#查看configmap
kubectl describe configmap test
#--from-file: 在创建configmap的时候指定文件, 将文件中的键值对, 作为参数
cd /root/configmap
vim /cm.txt
username=ls
passward=123456
kubectl create configmap test2 --from-file=./cm.txt
#查看configmap
kubectl describe configmap test```
4.3.1.2.2 yml创建
```Shell
cd /root/configmap
vim ./cm.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: default
  name: test3
data:   #定义数据
  username: "ww"
  password: "123456"
  my.cnf: |   #定义配置文件类型的数据, 文件是mysql的配置文件
    [mysqld]
    log-bin = "mysql-bin"
kubectl apply -f ./cm.yml
kubectl describe configmop test3 ```
4.3.1.2.3 环境变量运用configmap
```Shell
cd /root/configmap
#指定configmap中的键值对
vim ./test.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: test-cm-volume
spec:
  containers:
  - name: nginx
    image: docker.1ms.run/library/nginx
    env: #声明环境变量
      - name: USERNAME #定义环境变量名称
        vauleFrom: #声明值的来源
          configMapKeyRef:
            name: test3   #config的名称
            key: username  #取test3中的username给容器环境变量USERNAME
kebectl apply -f ./test.yml
kubectl get pod
kubectl exec -it test-cm-volume /bin/bash
echo "$USERNAME"
#指定整个configmap
vim ./test2.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: test-cm-volume2
spec:
  containers:
  - name: nginx
    image: docker.1ms.run/library/nginx
    envFrom: #声明
      - configMapRef:  #声明引用的configmap的名称
          name: test3
kebectl apply -f ./test2.yml
kubectl get pod
kubectl exec -it test-cm-volume2 /bin/bash
env```
4.3.1.2.4 卷挂载使用
```YAML
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: docker.1ms.run/library/nginx
    volumeMounts:   #引用卷
    - name: config-volume4  #引用卷的名称
      mountPath: "/tmp/configmap"    #引用后挂载到容器的目录
  volumes:  #声明卷
  - name: config-volume4   #定义卷名称  
    configMap:   #声明卷中携带configmap
      name: test3```
4.3.1.4.5 使用subpath将configmap作为文件挂载
```Shell
#注意
  #subepath引用的挂载不会对挂载目录原内容进行覆盖
  #卷挂载后, 容器中原目录中的内容会被覆盖
  #使用env形式对configmap挂载, configmap更新后, 容器不会更新
  #使用卷形式对configmap挂载, configmap更新后, 容器自动会更新
cp /etc/nginx/nginx.conf /root/configmap
cd /root/configmap
#修改nginx配置文件
vim ./nginx.conf
user nginx;
worker_processes 1;   #修改
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 2048;  #修改
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}
#创建configmap
#nginx.conf会成为nginx这个cm中的名称, 值为文件中改的内容
kubectl create configmap nginx --from-file=./nginx.conf
#查看configmap
kubectl describe configmap nginx -n default 
#定义pod, 并挂载configmap
vim sub.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: nginx-subpath
spec:
  containers:
    - name: nginx-web
      image: docker.1ms.run/library/nginx
      volumeMounts:   #引用卷
        - name: nginxconf  #引用卷的名称
          mountPath: /etc/nginx/nginx.conf  #将卷中的内容挂载到该目录
          subPath: nginx.conf   #挂载后, 只对nginx.conf文件进行替换, 不影响目录内其他内容, 保证与volums.path: nginx.conf对应
  volumes:  #定义卷
    - name: nginxconf   #卷名称
      configMap:  #引用configmap
        name: nginx  #configmap的名称
        items:  #声明引用configmap中具体的键值对
          - key: nginx.conf  #configmap中的key
            path: nginx.conf  #configmap中的路径
kubectl apply -f ./sub.yml
kubectl get pod -n default
kubectl exec -it nginx-subpath /bin/bash
ls /etc/nginx  #验证目录内容是否被覆盖
cat /etc/nginx/nginx.conf  #验证文件是否被修改```
4.3.1.3 downward api
1. 定义: 用于在容器中获取pod的信息
注意:
  1. 环境变量: 用于容器获取pod的单个变量, 直接将pod信息注入容器内
  2. 卷挂载: 将pod信息生成为文件, 挂载到容器指定目录
4.3.1.3.1 环境形式获取pod信息
```Shell
#注意:
   #对于不变的数据(元数据), 可以直接引用
   #对于变化的数据(状态数据), 使用status.变量名
mkdir /root/da
cd /root/da
vim ./env-da.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: env-pod
  labels:
    name: env-pod
spec:
  containers:
    - name: nginx
      image: docker.1ms.run/library/nginx
      env:  #声明环境变量
        - name: PODNAME  #变量名
          valueFrom:   #值来源
            fieldRef:   #关联字段
              fieldPath: metadata.name  #字段路径
        - name: PODNAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: PODIP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP  #由于ip在pod重建时都会变, 属于状态数据, 使用status
kubectl apply -f ./env-da.yml
kubectl exec -it env-pod /bin/bash
echo "$PODNAME" && echo "$PODNAMESPACE" && echo "$PODIP"```
4.3.1.3.2 卷挂载形式获取pod信息
```Shell
cd /root/da
vim ./vol.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
  namespace: kube-system 
  labels:
    k8s-app: test-volume
    node-env: test
spec:
  containers:
    - name: container
      image: docker.1ms.run/library/nginx
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "labels"
            fieldRef:
              fieldPath: metadata.labels
kubectl apply -f ./vol.yml
kubectl exec -it volume-pod /bin/bash -n kube-system
cd /etc/podinfo/
ls
cat labels```
4.3.1.4 serviceaccount
1. 定义: pod容器中的进程访问apiserver时, 会被看做特定的serviceaccount
注意:
  1. 当用户访问集群时, apiservice会将用户看做useraccount
  2. 每个命名空间中都会有SA
  3. 每创建一个SA, token控制器就会为该SA生成一个用于访问k8s集群api的token与ca证书等资源
  4. pod中的每个容器都会默认挂载当前命名空间下的SA, 从而实现容器内进程访问k8s集群api
  5. 每个SA都有生成一个secret
4.3.1.4.1 引用SA
```Shell

mkdir /root/sa
vim ./sa.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: website
  labels:
    app: website
spec:
  containers:
    - name: test-web
      image: docker.1ms.run/library/nginx
      ports:
        - containerPort: 80
  serviceAccount: mysa   #指定SA名称
  #查看SA
  kubectl get sa -n default

4.3.2 普通卷
4.3.2.1 hostPath

mkdir /var/data
echo "linux" > /var/data/index.html
chmod 777 /var/data/index.html
vim nginx-dep1.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      nodeName: node1 #必须指定调度到node1上,因为node1上才有/var/data⽬
      containers:
      - name: nginx
        image: daocloud.io/library/nginx
        ports:
        - containerPort: 80
          volumeMounts: #定义挂载卷
          - mountPath: "/usr/share/nginx/html"
            name: nginx-vol
      volumes: #定义共享卷
      - name: nginx-vol
        hostPath:
        path: /var/data```
4.3.3 pvc/pv(第八章)
4.5 集群管理类
4.5.1 namespace
4.5.1.1 namespace
1. 定义: 为k8s资源提供命名作用域, 资源名称在同一命名空间必须唯一
2. 作用: 是集群资源逻辑层面上的隔离, 实现不同命名空间的共享物理层资源, 但权限与名称的隔离 
4.5.1.2 默认namespace
1. default: 未指定命名空间的资源对象的默认命名空间
2. kube-system: k8s系统组件(api-server, controller-manager等)
3. kube-public: 公共资源, 所有用户都可访问的对象
4. kube-node-lease: 用于节点的心跳检测
4.5.1.3 namespace的状态
1. active: 活跃状态
2. terminating: 删除中
4.5.1.4 namespace操作
```Shell
#创建命名空间
mkdir /root/ns
cd /root/ns
#定义命名空间对象ns-monitor
vim ./namespace.yml
---
apiVersion: v1  #apiserver支持ns的版本
kind: Namespace  #资源对象类型: 命名空间
metadata:   #命名空间源数据, 命名空间属性
  name: ns-monitor  #命名空间对象的名称
  labels:   #命名空间对象的标签
    name: ns-monitor   #该命名空间对象的标签
#执行命令, 创建该命名空间
kubectl apply -f ./namespace.yml
#查询命名空间
kubectl get ns ns-monitor
#查看命名空间的详细信息
kubectl describe ns ns-monitor
#删除命名空间
kubectl delete -f namespace.yml
kubectl delete ns-monitor```
第五章 基于角色的访问控制(RBAC)
5.1 RBAC
1. 定义: 用户通过角色, 来获得权限, 从而实现对资源的操作
注意:
  1. sa是pod访问apiservice的权限认证
  2. 每个pod中都会由于默认的sa, 除非该pod指定了其他sa
5.2 RBAC的对象
5.2.1 role
1. 命名空间内权限的集合
5.2.2 clusterRole
1. 集群权限的集合
注意:
  1. 没有命名空间的限制, 可以调度整个集群的资源
5.2.3 roleBinding
1. 角色与role的绑定关系
注意:
  1. 仅在某一命名空间中有效
5.2.4 clusterRoleBinding
2. 角色与clusterRole的绑定关系
注意:
  1. 在整个集群有效
5.3 RBAC的角色
5.3.1 user
1. 外部用户
5.3.2 serviceaccount
1. 容器中的进程
5.4 使用RBAC
5.4.1 user+rolebinding(当前命名空间有效:default)
1. 创建用户访问k8s的私钥
```Shell
(umask 077; openssl genrsa -out cc.key 2048)```
2. 创建证书签名请求文件
```Shell
openssl req -new -key cc.key -out cc.csr -subj "/CN=cc"```
3. 根据证书签名请求文件与私钥生成证书
```Shell
openssl x509 -req -in cc.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out cc.crt -days 365```
4. 创建外部账号
```Shell
kubectl config set-credentials cc --client-certificate=cc.crt --client-key=cc.key --embed-certs=true```
5. 配置账号的可使用环境
```Shell
#查看当前的上下文环境
kubectl config view
#为cc账户配置上下文环境
kubectl config set-context cc@kubernetes --cluster=kubernetes --user=cc```
6. 创建角色并绑定用户
```Shell
#创建角色
#verb: 指定权限
#resource: 指定操作对象
kubectl create role myrole --verb=get,list,watch --resource=pod,svc
#将角色绑定用户cc
kubectl create rolebinding myrole-binding --role=myrole --user=cc```
7. 切换用户
```Shell
kubectl config use-context cc@kubernetes```
8. 验证
```Shell
#验证用户的上下文环境是否切换
kubectl config current-context
#查看pod与service
kubectl get pod,service```
9. 删除cc用户与角色的绑定
```Shell
kubectl delete rolebinding myrole-binding```
5.4.2 user+clusterRoleBinding(没有ns限制)
1. 创建clusterRole类型的角色
```Shell
kubectl create clusterrole myclusterrole --verb=get,list,watch  --resource=pod,svc```
2. 将cc用于与该角色绑定
```Shell
kubectl create clusterrolebinding my-cluster-role --clusterrole=myclusterrole --user=cc```
3. 切换用户
```Shell
kubectl config use-context cc@kubernetes```
4. 验证权限
```Shell
kubectl get pod,service -n default
kubectl get pod,service -n kube-system```
5.4.3 serviceaccount+clusterRoleBinding()
1. 定义sa
```Shell
cd /root/rbac
vim ./sa.yml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: kube-system
  name: sa
  labels:
      name: sa
kubectl apply -f ./sa.yml```
2. 定义clusterrolebinding
```Shell
cd /root/rbac
vim ./cr.yml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: sa-cr-binding
  labels:
      name: sa-cr-binding
roleRef:  #声明角色
    apiGroup: rbac.authorization.k8s.io
    kind: ClusterRole
    name: cr
subjects:  #引用sa
  - kind: ServiceAccount
    namespace: kube-system
    name: sa
kubectl apply -f ./cr.yml```
3. 创建pod并指定sa
```Shell
cd /root/rbac
vim ./pod.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: kube-system
  name: pod
spec:
  serviceAccountName: sa  #该pod使用该sa与api进行交互
  containers:
  - name: nginx
    image: docker.1ms.run/library/nginx
kubectl apply -f ./pod.yml```
第六章 容器监控检查与恢复机制
6.1 容器监控检查
1. 定义: 为pod中的容器定义一个反应容器健康状态的探针(probe), 探针会将检测结果上报kubelet组件, 之后kubelet组件, 会判断容器的健康状态
注意:
  1. 容器恢复机制: 若容器的检测结果为非健康, 那么该容器就会被重新创建, 而pod会继续保持running
  2. 容器重建后pod的ip不变, 只有pod重建, ip才会变
6.2 探针的类型
1. 存活探针: 判断容器是否正常运行
2. 就绪探针: 判断容器是否准备好接收请求
3. 启动探针: 判断容器是否启动成功
6.3 存活探针的检测方式
6.3.1 命令(exec)模式
1. 定义: 在容器内执行自定义命令, 通过命令的退出码, 判断容器健康状态
注意:
  1. 退出码=0, 容器健康
  2. 退出码!=0, 容器不健康
6.3.1.1 应用exec模式
```Shell
cd /root/li
#定义pod
vim ./exec.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: pod-exec
spec:
  containers:
  - name: web-nginx
    image: docker.1ms.run/library/nginx
    args:  #容器启动后, 创建healthy文件, 若创建成功, 表示容器健康; 若创建失败, 或删除文件, 表示容器不健康
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 60; rm -rf /tmp/healthy; sleep 60
    livenessProbe:  #引用存活探针
      exec:  #exec类型的存活探针
        command:  #执行的命令
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5  #健康检查的启动时间为容器启动5s后执行
      periodSeconds: 5  #健康检查的频率为每5s执行一次
kubectl apply -f ./exec.yml
#每2min观察restart字段的变化
kubectl get pod pod-exec -o wide```
6.3.2 httpGet模式
1. 定义: 向容器的指定ip+port+路径, 发送http/https请求, 通过响应状态码判断容器的健康状态
注意
  1. 2xx或3xx, 容器健康
  2. 4xx或5xx, 容器不健康
6.3.2.1 应用httpget模式
```Shell
cd /root/li
#定义pod
vim ./httpget.yml
---
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: pod-http
spec:
  containers:
  - name: web-nginx
    image: docker.1ms.run/library/nginx
    ports:
      - containerPort: 80
        name: http  #为80端口定义别名
    livenessProbe:
      httpGet:
        port: http  #引用80端口, 探针会访问80端口下的index.html文件 
        path: /index.html  #容器创建成功后, 会在/usr/share/nginx/html下有index.html文件
      initialDelaySeconds: 3   #探针会在启动3s后开始检测
      periodSeconds: 3  #每3s执行一次
kubectl apply -f ./httpget.yml
#查看pod是否running
kubectl get pod pod-http -o wide
#进入pod
kubectl exec -it pod-http /bin/bash
#删除index.html文件
rm -rf /usr/share/nginx/html/index.html
#查看pod重启次数
kubectl get pod pod-http -o wide```
6.4 恢复机制
6.4.1 恢复机制的三种方式
1. always: 默认的, 只要容器不在运行状态, 就会重新创建容器
2. onfailure: 只有在容器异常时, 才会重新创建容器
3. never: 永远不-重新创建容器
第七章 pod管理
7.1 弹性伸缩
1. 修改控制器中的replicas的数量, 并重新apply即可
注意:
  1. 使用kubectl edit deployment dep01或vim原yml文件都可以
7.2 滚动升级
1. 主要修改副本控制器的名称与容器的镜像版本即可
注意:
  1. 使用kubectl edit deployment dep01或vim原yml文件都可以
  2. 滚动更新的优势: 在更细过程中, 旧的pod不会终止, 只有更新完成后旧版本才会终止, 保证服务的不间断运行
7.3 版本回滚
1. 查看历史版本: kubectl rollout history deployment dep02
2. 回滚上一个版本: kubectl rollout undo deployment dep02
3. 查看指定版本的详细信息: kubectl rollout history deployment dep02 --revision=3
4. 回滚到更早的版本: kubectl rollout undo deployment dep02 --to-revision=2
5. 查看回滚状态: kubectl rollout status deployment dep02
注意: 
  1. 只有创建对象时使用了--record参数, 才支持回到更早的版本 
第八章 pvc/pv
8.1 定义
1. 实现资源的持久化存储, 解决pod重启或重建后数据的丢失问题
8.2 组件
1. pv: 集群的持久化存储资源, 独立于pod的生命周期
2. pvc: 用户向集群申请pv的声明, 集群自动匹配符合条件的pv
8.3 pv回收策略
1. retain: 删除pvc后, 仍会关联原命名空间, 无法被新的pvc绑定, 需手动才能重新绑定
2. delete: 删除pvc后, 自动删除pv的资源, 数据无法恢复
8.4.pv供应
1. pv静态供应: 需要通过pvc向pv申请空间, 需要提前创建pv
2. pv动态供应: 若没有符合pvc条件的pv, 那么就会动态创建pv, 不需要提前创建pv
8.5 应用
8.5.1 配置NFS
1. 三台主机安装nfs
```Shell
yum -y install nfs-common ufs-utils```
2. 在nfs-server上创建共享目录, 并授权
```Shell
mkdir /nfsdata
chmod 666 /nfs```
3. 编辑exports文件
```Shell
echo "/nfsdata *(rw,no_root_squash,no_all_squash,sync)" >> /etc/exports```
4. 启动nfs
```Shell
systemctl start rpcbind
systemctl start nfs```
8.3.2 创建pv
```Shell
vim ./nfs-pv1.yml
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv1
spec:
  capacity:  #定义pv容量为1G
    storage: 1Gi
  accessModes:
    - ReadWriteOnce  #挂载该pv的主机, 对该pv拥有读写权限, 并且只能单节点挂载
  persistentVolumeReclaimPoliy: Retain  #pv会回收策略
  storageClassName: nfs  #pv的类型
  nfs:
    path: /nfsdata  #定义pv目录
    server: 192.168.255.130  #定义pv的宿主机
kubectl apply -f nfs-pv1.yml
kubectl get pv```
8.3.3 创建pvc
```Shell
vim ./nfs-pvc1.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc1
spec:
  accessModes:
    - ReadWriteOnce  
  resources:
    requests:  #申请
      storage: 1Gi  #申请大小
  storageClassName: nfs  #向名称为nfs的pv申请
kubectl apply -f nfs-pvc1.yml
kubectl get pvc```
8.3.4 创建pod, 使用pv
```Shell
vim ./pod.yml
---
apiVersion: v1
kind: pod
metadata:
  name: mypod1
  labels:
    app: test
spec:
  containers:
    - name: mypod
      image: 10.8.166.241/nginx/nginx:v1.1
      ports:
      - containerPort: 80
      volumeMounts:#引用卷
      - mountPath: "/usr/share/nginx/html"  #将卷挂载到该目录
        name: mydata  #引用卷的名称
  volumes:  #定义卷
    - name: mydata
      persistentVolumeClaim: #引用创建的pvc:mypvc1
        claimName: mypvc1        
kubectl apply -f pod.yml```
8.3.5 测试
```Shell
kubectl exec -it mypod1 /bin/bash
echo "test" > /usr/share/nginx/html/index.html
#nfs服务器查看
cat /nfsdata/index.html```
8.3.6 回收pv
```Shell
#删除pod
kubectl delete pod mypod1
#删除pvc, 注意删除pvc或pv后, 数据在nfs上任然存在, 
kubectl delete pvc mypvc1```

更多推荐