kubernetes ubuntu安装部署

安装基础环境

配置系统hosts文件

 cat >> /etc/hosts <<EOF

10.10.34.92   ukm01
10.10.34.93   ukm02
10.10.34.94   ukm03
10.10.34.95   uki01
10.10.34.96   uki02
10.10.34.97   uki03
10.10.34.98   ukn01
10.10.34.99   ukn02
10.10.34.100  ukn03
EOF

配置主机名

hostnamectl set-hostname ukm01

配置sshkey

创建sshkey

 ssh-keygen -t dsa -b 1024 -C "seanzhau@mokr.cn"
Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
The key fingerprint is:
SHA256:LaO+CdmwvXlHaIPXvZf0s/XjKxPjVUdtvoHC0PCGEUs seanzhau@mokr.cn
The key's randomart image is:
+---[DSA 1024]----+
|         E+     .|
|        ..=.    +|
|         ooo  .+ |
|         ..o . .+|
|    .  .So...   =|
|     *..=oo .o.o |
|    + +o o  .o+o.|
|     o +. . .+oo+|
|      *o .   .++*|
+----[SHA256]-----+

分发key

 ssh-copy-id ukm01
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_dsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1
...

 ssh-copy-id ukn03
...

校验

 ssh ukm01
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-88-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

 System information disabled due to load higher than 4.0
...

 ssh ukn03
...

配置阿里云 repo

 mv /etc/apt/sources.list /etc/apt/sources.list.bak

 cat > /etc/apt/sources.list <<EOF
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

EOF

安装基础包

ubuntu 18.04 默认未安装python,需要每台服务器手动安装。

apt update && apt install -y software-properties-common apt-transport-https ca-certificates gnupg2 python curl

安装 ansible

只需在 master 节点安装

apt-add-repository --yes --update ppa:ansible/ansible

apt install -y ansible

配置 ansible.cfg

 cat > /etc/ansible/ansible.cfg <<EOF
[defaults]
log_path = /var/log/ansible.log

forks = 20
host_key_checking = False
retry_files_enabled = False
deprecation_warnings = False
nocows = True
remote_user = root
roles_path = roles/
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /etc/ansible/facts
fact_caching_timeout = 600
callback_whitelist = profile_tasks
inventory_ignore_extensions = secrets.py, .pyc, .cfg, .crt, .ini
timeout = 30

[inventory]
unparsed_is_failed=true

[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=600s
timeout = 10
control_path = %(directory)s/%%h-%%r
EOF

配置 inventory hosts

 cat > /etc/ansible/hosts <<EOF
[ins]
10.10.34.92  hostname='ukm01'
10.10.34.93  hostname='ukm02'
10.10.34.94  hostname='ukm03'
10.10.34.95  hostname='uki01'
10.10.34.96  hostname='uki02'
10.10.34.97  hostname='uki03'
10.10.34.98  hostname='ukn01'
10.10.34.99  hostname='ukn02'
10.10.34.100 hostname='ukn03' ansible_ssh_user='root' ansible_ssh_pass='xxxxxxx'

[ans]
10.10.34.92

[master]
10.10.34.9[2:4]

[infra]
10.10.34.9[5:7]

[worker]
10.10.34.9[8:9]
10.10.34.100
EOF

验证 ansible 配置

 ansible ins -m ping
10.10.34.92 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
...

集群节点绑定主机名

 ansible ins:\!ans -m shell -a 'cat >> /etc/hosts <<EOF
10.10.34.92   ukm01
10.10.34.93   ukm02
10.10.34.94   ukm03
10.10.34.95   uki01
10.10.34.96   uki02
10.10.34.97   uki03
10.10.34.98   ukn01
10.10.34.99   ukn02
10.10.34.100  ukn03
EOF'

 ansible ins:\!ans -m shell -a 'cat /etc/hosts'

分发配置

分发私钥
ansible master -m copy -a 'src=/root/.ssh/id_rsa dest=/root/.ssh/id_rsa mode=0600 owner=root'

分发 ansible 配置
ansible master -m copy -a 'src=/etc/ansible/hosts dest=/etc/ansible/hosts'

ansible master -m copy -a 'src=/etc/ansible/ansible.cfg dest=/etc/ansible/ansible.cfg'

安装 Docker CE

添加 Docker GPG key

ansible ins -m shell -a 'curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -'

配置 Docker 源

  • 动态识别操作系统版本 add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
ansible ins -m shell -a 'add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu bionic stable"'

安装 Docker

ansible ins -m shell -a 'apt update && apt install -y docker-ce docker-ce-cli containerd.io'

配置 docker daemon

 cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "5"
  },
  "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"],
  "storage-driver": "overlay2"
}
EOF

分发 daemon.json

ansible ins -m copy -a 'src=/etc/docker/daemon.json dest=/etc/docker/daemon.json'

ansible ins -m shell -a 'mkdir -p /etc/systemd/system/docker.service.d'

重启 docker 服务

ansible ins -m shell -a 'systemctl daemon-reload'

ansible ins -m shell -a 'systemctl restart docker'

ansible ins -m shell -a 'docker info|grep -i cgroup'
Cgroup Driver: systemd

daemon.json 配置详解

 cat /etc/docker/daemon.json
{
  "authorization-plugins": [],
  "data-root": "",
  "dns": [],
  "dns-opts": [],
  "dns-search": [],
  "exec-opts": [],
  "exec-root": "",
  "experimental": false,
  "features": {},
  "storage-driver": "",
  "storage-opts": [],
  "labels": [],
  "live-restore": true,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file":"5",
    "labels": "somelabel",
    "env": "os,customer"
  },
  "mtu": 0,
  "pidfile": "",
  "cluster-store": "",
  "cluster-store-opts": {},
  "cluster-advertise": "",
  "max-concurrent-downloads": 3,
  "max-concurrent-uploads": 5,
  "default-shm-size": "64M",
  "shutdown-timeout": 15,
  "debug": true,
  "hosts": [],
  "log-level": "",
  "tls": true,
  "tlsverify": true,
  "tlscacert": "",
  "tlscert": "",
  "tlskey": "",
  "swarm-default-advertise-addr": "",
  "api-cors-header": "",
  "selinux-enabled": false,
  "userns-remap": "",
  "group": "",
  "cgroup-parent": "",
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 64000,
      "Soft": 64000
    }
  },
  "init": false,
  "init-path": "/usr/libexec/docker-init",
  "ipv6": false,
  "iptables": false,
  "ip-forward": false,
  "ip-masq": false,
  "userland-proxy": false,
  "userland-proxy-path": "/usr/libexec/docker-proxy",
  "ip": "0.0.0.0",
  "bridge": "",
  "bip": "",
  "fixed-cidr": "",
  "fixed-cidr-v6": "",
  "default-gateway": "",
  "default-gateway-v6": "",
  "icc": false,
  "raw-logs": false,
  "allow-nondistributable-artifacts": [],
  "registry-mirrors": [],
  "seccomp-profile": "",
  "insecure-registries": [],
  "no-new-privileges": false,
  "default-runtime": "runc",
  "oom-score-adjust": -500,
  "node-generic-resources": ["NVIDIA-GPU=UUID1", "NVIDIA-GPU=UUID2"],
  "runtimes": {
    "cc-runtime": {
      "path": "/usr/bin/cc-runtime"
    },
    "custom": {
      "path": "/usr/local/bin/my-runc-replacement",
      "runtimeArgs": [
        "--debug"
      ]
    }
  },
  "default-address-pools":[
    {"base":"172.80.0.0/16","size":24},
    {"base":"172.90.0.0/16","size":24}
  ]
}

格式化查看 images

  • .ID Image ID
  • .Repository Image 仓库地址和名称
  • .Tag Image 标签
  • .Digest Image hash 值信息
  • .CreatedSince Image 创建到现在的时间
  • .CreatedAt Image 创建的具体时间
  • .Size Image 大小
docker images --format "table {{ .Repository }} \t {{ .Tag }} \t {{ .ID }} \t {{ .CreatedSince }} \t {{ .CreatedAt }} \t {{ .Size }}" --digests

docker pull 过程

  • Docker 客户端发送 REPOSITORY 和 TAG(或者 DIGEST)给 Registry;
  • Registry 根据 REPOSITORY 和 TAG(或者 DIGEST)找到相应 image manifest;
  • Registry 将 manifest 返回给 Docker 客户端;
  • Docker 客户端根据 manifest 读取 image 的 digest(sha256) , sha256 就是 IMAGE ID;
  • Docker 客户端根据 ID 查找本地是否存在对应的 image;
  • 如果 image 存在则创建对应的 image REPOSITORY 和 TAG;
  • 如果 image 不存在,则继续请求 Registry 获取 image 的配置文件;
  • 根据 image 配置文件中的 diff_ids 在本地找对应的 layer 是否存在;
  • 如果 layer 存在,则返回 Already exists;
  • 如果 layer 不存在,则根据 manifest 中 layer 的 sha256 和 media type 去服务器下载对应的 layer;
  • 下载解压之后,校验 tar 包的 sha256 是否和 Image Config 中的 diff_id 一致。

image本地存放信息

 查看 image DIGEST 信息
 docker images --digests
REPOSITORY                    TAG                 DIGEST                                                                    IMAGE ID            CREATED             SIZE
busybox                       latest              sha256:a8cf7ff6367c2afa2a90acd081b484cbded349a7076e7bdf37a05279f276bc12   be5888e67be6        2 weeks ago         1.22MB

 如果是其他的文件系统的话,名字会是其他的,比如btrfs、overlay2、devicemapper等。
 cat /var/lib/docker/image/overlay2/repositories.json | python -m json.tool
{
    "Repositories": {
        "busybox": {
            "busybox:latest": "sha256:be5888e67be651f1fbb59006f0fd791b44ed3fceaa6323ab4e37d5928874345a",
            "busybox@sha256:a8cf7ff6367c2afa2a90acd081b484cbded349a7076e7bdf37a05279f276bc12": "sha256:be5888e67be651f1fbb59006f0fd791b44ed3fceaa6323ab4e37d5928874345a"
        }
    }
}

 校验 image config 的 sha256 值
 sha256sum /var/lib/docker/image/overlay2/imagedb/content/sha256/be5888e67be651f1fbb59006f0fd791b44ed3fceaa6323ab4e37d5928874345a
be5888e67be651f1fbb59006f0fd791b44ed3fceaa6323ab4e37d5928874345a  /var/lib/docker/image/overlay2/imagedb/content/sha256/be5888e67be651f1fbb59006f0fd791b44ed3fceaa6323ab4e37d5928874345a

 查看 image config
 cat /var/lib/docker/image/overlay2/imagedb/content/sha256/be5888e67be651f1fbb59006f0fd791b44ed3fceaa6323ab4e37d5928874345a | python -m json.tool
{
    "architecture": "amd64",
    "config": {
        "ArgsEscaped": true,
        "AttachStderr": false,
        "AttachStdin": false,
        "AttachStdout": false,
        "Cmd": [
            "sh"
        ],
        "Domainname": "",
        "Entrypoint": null,
        "Env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "Hostname": "",
        "Image": "sha256:b0acc7ebf5092fcdd0fe097448529147e6619bd051f03ccf25b29bcae87e783f",
        "Labels": null,
        "OnBuild": null,
        "OpenStdin": false,
        "StdinOnce": false,
        "Tty": false,
        "User": "",
        "Volumes": null,
        "WorkingDir": ""
    },
    "container": "f7e67f16a539f8bbf53aae18cdb5f8c53e6a56930e7660010d9396ae77f7acfa",
    "container_config": {
        "ArgsEscaped": true,
        "AttachStderr": false,
        "AttachStdin": false,
        "AttachStdout": false,
        "Cmd": [
            "/bin/sh",
            "-c",
            "(nop) ",
            "CMD [\"sh\"]"
        ],
        "Domainname": "",
        "Entrypoint": null,
        "Env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "Hostname": "f7e67f16a539",
        "Image": "sha256:b0acc7ebf5092fcdd0fe097448529147e6619bd051f03ccf25b29bcae87e783f",
        "Labels": {},
        "OnBuild": null,
        "OpenStdin": false,
        "StdinOnce": false,
        "Tty": false,
        "User": "",
        "Volumes": null,
        "WorkingDir": ""
    },
    "created": "2020-04-14T19:19:53.590635493Z",
    "docker_version": "18.09.7",
    "history": [
        {
            "created": "2020-04-14T19:19:53.444488372Z",
            "created_by": "/bin/sh -c (nop) ADD file:09a89925137e1b768ef1f0e7d1d7325eb2b4f1a0895b3aa8dfc98b0c75f3f507 in / "
        },
        {
            "created": "2020-04-14T19:19:53.590635493Z",
            "created_by": "/bin/sh -c (nop)  CMD [\"sh\"]",
            "empty_layer": true
        }
    ],
    "os": "linux",
    "rootfs": {
        "diff_ids": [
            "sha256:5b0d2d635df829f65d0ffb45eab2c3124a470c4f385d6602bda0c21c5248bcab"
        ],
        "type": "layers"
    }
}

 layer diff_id 和 digest 的对应关系
 diffid-by-digest: 存放 digest 到 diffid 的对应关系
 v2metadata-by-diffid: 存放 diffid 到 digest 的对应关系
 tree /var/lib/docker/image/overlay2/distribution/
/var/lib/docker/image/overlay2/distribution/
├── diffid-by-digest
│   └── sha256
│       ├── e2334dd9fee4b77e48a8f2d793904118a3acf26f1f2e72a3d79c6cae993e07f0
│       └── ec237e1426f0de497da8c0951d5db1d2b7f155d207cfc0df02f3fb0508a3036a
└── v2metadata-by-diffid
    └── sha256
        ├── 5b0d2d635df829f65d0ffb45eab2c3124a470c4f385d6602bda0c21c5248bcab
        └── f53db92a80829925f8ec12396ab68569d7a769d9ab94983b86dbe6b26ae3d1fa

 根据 diffid 获取 digest
~ cat /var/lib/docker/image/overlay2/distribution/v2metadata-by-diffid/sha256/5b0d2d635df829f65d0ffb45eab2c3124a470c4f385d6602bda0c21c5248bcab | python -m json.tool
[
    {
        "Digest": "sha256:e2334dd9fee4b77e48a8f2d793904118a3acf26f1f2e72a3d79c6cae993e07f0",
        "HMAC": "",
        "SourceRepository": "docker.io/library/busybox"
    }
]

 根据 digest 获取 diffid
 cat /var/lib/docker/image/overlay2/distribution/diffid-by-digest/sha256/e2334dd9fee4b77e48a8f2d793904118a3acf26f1f2e72a3d79c6cae993e07f0
sha256:5b0d2d635df829f65d0ffb45eab2c3124a470c4f385d6602bda0c21c5248bcab

 根据 digest 查看 layer 元数据
 cd /var/lib/docker/image/overlay2/layerdb/sha256/5b0d2d635df829f65d0ffb45eab2c3124a470c4f385d6602bda0c21c5248bcab/ && ls -l
total 24
-rw-r--r-- 1 root root    64 Apr 30 15:21 cache-id
-rw-r--r-- 1 root root    71 Apr 30 15:21 diff
-rw-r--r-- 1 root root     7 Apr 30 15:21 size
-rw-r--r-- 1 root root 12159 Apr 30 15:21 tar-split.json.gz

 cache-id 是 docker 下载 layer 的时候随机生成 uuid,指向真正存放 layer 文件的位置。
 cat cache-id
486d3aacd2ee026b1e3db99b23e32a9f60d0972f7224fd53657a41943c871872

 diff 文件存放 layer 的 diffid
 cat diff
sha256:5b0d2d635df829f65d0ffb45eab2c3124a470c4f385d6602bda0c21c5248bcab

 size 当前 layer 的大小,单位是字节。
 tar-split.json.gz 是 layer 的 split 文件,通过这个文件可以还原 layer 的 tar 包,在 docker save 导出 image 时会用到。

 layer 数据,image 存储数据,使用 cache-id 访问。
 cd /var/lib/docker/overlay2/486d3aacd2ee026b1e3db99b23e32a9f60d0972f7224fd53657a41943c871872
 tree -d diff/
diff/
├── bin
├── dev
├── etc
│   └── network
│       ├── if-down.d
│       ├── if-post-down.d
│       ├── if-pre-up.d
│       └── if-up.d
├── home
├── root
├── tmp
├── usr
│   └── sbin
└── var
    ├── spool
    │   └── mail
    └── www

 manifest 存储对 config 和 layer 的 sha256 + media type 描述,目的就是为了下载 config 和 layer。下载完成后,manifest 的使命就完成了,所以在本地没有存储 manifest 文件。

docker 空间管理

 查看空间
 docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              11                  9                   1.084GB             202.9MB (18%)
Containers          18                  12                  10.61kB             0B (0%)
Local Volumes       0                   0                   0B                  0B
Build Cache         0                   0                   0B                  0B

 清理文件系统
 docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N]

 强制清理,忽略依赖关系。
 docker system prune -a -f

 清理所有状态为 <none> 的 image
 docker image prune
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N]

 强制清理 image,忽略依赖关系。
 docker image prune -a
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N]

 清理无用数据卷
 docker volume ls
 docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N]

 清理所有停止的容器
 docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N]

配置系统

内核关闭 swap

ansible ins -m shell -a 'echo "vm.swappiness = 0" >> /etc/sysctl.conf && sysctl -p'

零时关闭 swap

ansible ins -m shell -a 'swapoff -a'

系统 fstab 关闭配置

ansible ins -m shell -a "sed -i 's/^[^#].*swap*/#&/g'  /etc/fstab && chattr +i /etc/fstab"
  • WARNING: No swap limit support
sed -i '/GRUB_CMDLINE_LINUX=/cGRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 console=tty0 console=ttyS0,115200 cgroup_enable=memory swapaccount=1"' /etc/default/grub

ansible ins -m copy -a 'src=/etc/default/grub dest=/etc/default/grub'

ansible ins -m shell -a 'update-grub && shutdown -r +1 "reboot for turnoff swap"'

安装 kubernetes

  • 激活旧版本的防火墙配置(19年之后的操作系统需要修改)
apt install -y iptables arptables ebtables

update-alternatives --set iptables /usr/sbin/iptables-legacy

update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

update-alternatives --set arptables /usr/sbin/arptables-legacy

update-alternatives --set ebtables /usr/sbin/ebtables-legacy

配置 kubernetes repo

批量配置
ansible ins -m shell -a 'curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -'

ansible ins -m shell -a 'add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main"'

安装 kubernetes 基础工具

查看当前支持的版本信息
apt-cache policy kubeadm

ansible ins -m shell -a 'apt update && apt install -y kubelet=1.17.3-00 kubeadm=1.17.3-00 kubectl=1.17.3-00'

配置 driver

 cat > /etc/default/kubelet <<EOF
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd
EOF

 cat > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf <<EOF
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --cgroup-driver=systemd"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# 这是 "kubeadm init" 和 "kubeadm join" 运行时生成的文件,动态地填充 KUBELET_KUBEADM_ARGS 变量
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# 这是一个文件,用户在不得已下可以将其用作替代 kubelet args。
# 用户最好使用 .NodeRegistration.KubeletExtraArgs 对象在配置文件中替代。
# KUBELET_EXTRA_ARGS 应该从此文件中获取。
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS

EOF

ansible ins -m copy -a 'src=/etc/default/kubelet dest=/etc/default/kubelet'
ansible ins -m copy -a 'src=/etc/systemd/system/kubelet.service.d/10-kubeadm.conf dest=/etc/systemd/system/kubelet.service.d/10-kubeadm.conf'

重启 kubelet

ansible ins -m shell -a 'systemctl daemon-reload && systemctl restart kubelet'

开启 ipvs 支持

配置内核支持 IP 转发

ansible ins -m shell -a 'grep net.ipv4.ip_forward /etc/sysctl.conf && sed -i "/net.ipv4.ip_forward/c\net.ipv4.ip_forward=1" /etc/sysctl.conf || echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf'
ansible ins -m shell -a 'grep net.bridge.bridge-nf-call-iptables /etc/sysctl.conf && sed -i "/net.bridge.bridge-nf-call-iptables/c\net.bridge.bridge-nf-call-iptables=1" /etc/sysctl.conf || echo "net.bridge.bridge-nf-call-iptables=1" >> /etc/sysctl.conf'
ansible ins -m shell -a 'grep net.bridge.bridge-nf-call-ip6tables /etc/sysctl.conf && sed -i "/net.bridge.bridge-nf-call-ip6tables/c\net.bridge.bridge-nf-call-ip6tables=1" /etc/sysctl.conf || echo "net.bridge.bridge-nf-call-ip6tables=1" >> /etc/sysctl.conf'

ansible ins -m shell -a 'sysctl -p'

配置内核加载 ipvs 模块

 cat > /tmp/ipvs.modules <<EOF
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack_ipv4"
for kernel_module in \${ipvs_modules}; do
    /sbin/modinfo -F filename \${kernel_module} > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        /sbin/modprobe \${kernel_module}
    fi
done
EOF

 ansible ins -m copy -a 'src=/tmp/ipvs.modules dest=/tmp/ipvs.modules mode=0755'
 ansible ins -m shell -a '/tmp/ipvs.modules'

 验证 ipvs 支持
 ansible ins -m shell -a 'lsmod | grep ip_vs'

安装 ipvsadm

ansible ins -m yum -a 'name=ipvsadm state=present'

创建 kubernetes 集群

ukm01 上执行

  • 内网负载均衡地址 10.10.34.89
 配置文件创建,可以修改较多的参数。
 cat > kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 0.0.0.0
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  kubeletExtraArgs:
    cgroup-driver: "systemd"
  ignorePreflightErrors:
  - IsPrivilegedUser
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
controlPlaneEndpoint: 192.168.0.113:6443
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
dns:
  type: CoreDNS
apiServer:
  timeoutForControlPlane: 5m0s
  extraArgs:
    authorization-mode: "Node,RBAC"
  certSANs:
  - "192.168.0.113"
  - "192.168.0.110"
  - "192.168.0.111"
  - "192.168.0.112"
  - "node1"
  - "node2"
  - "node3"
  - "kubernetes"
  - "kubernetes.default"
  - "kubernetes.default.svc"
  - "kubernetes.default.svc.cluster"
  - "kubernetes.default.svc.cluster.local"
controllerManager:
  extraArgs:
    "node-cidr-mask-size": "20"
scheduler:
  extraArgs:
    address: "0.0.0.0"
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
kubernetesVersion: v1.20.1
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
  podSubnet: 192.168.0.0/16
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
bindAddress: 0.0.0.0
mode: ipvs   
ipvs:
  scheduler: wlc
  syncPeriod: 30s
  minSyncPeriod: 5s
  tcpTimeout: 0s
  tcpFinTimeout: 0s
  udpTimeout: 0s
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
rotateCertificates: true
EOF


 验证 kubeadm-config 配置
 kubeadm init --config=kubeadm-config.yaml --upload-certs

 创建集群
 kubeadm init --config=kubeadm-config.yaml --upload-certs

 参数化创建集群
 kubeadm init \
  --apiserver-bind-port 8443 \
  --control-plane-endpoint "10.10.34.89:8443" \
  --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
  --kubernetes-version=v1.17.3 \
  --upload-certs \
  --pod-network-cidr=10.100.0.0/16 \
  --service-cidr=10.96.0.0/12 \

...
kubeadm join 10.10.34.89:8443 --token 7nf8wp.cefgemzgn5xcdmln \
    --discovery-token-ca-cert-hash sha256:36b328e0052c7f8e7cac826d70b21bef0cdc4e0505fddc8200c52b8b01605da3 \
    --control-plane --certificate-key bd9fc1600d2db4f2b323a17b2b7be4f4234d7ed8705bc64976dcd43d929a24a8
...
kubeadm join 10.10.34.89:8443 --token 7nf8wp.cefgemzgn5xcdmln \
    --discovery-token-ca-cert-hash sha256:36b328e0052c7f8e7cac826d70b21bef0cdc4e0505fddc8200c52b8b01605da3

kubeadm init 常用参数

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

master 节点扩容

在 ukm02 ukm03 上执行

ansible master:\!ans -m shell -a 'kubeadm join 10.10.34.89:8443 \
   --apiserver-bind-port 8443 \
   --control-plane \
   --token 7nf8wp.cefgemzgn5xcdmln \
   --discovery-token-ca-cert-hash sha256:36b328e0052c7f8e7cac826d70b21bef0cdc4e0505fddc8200c52b8b01605da3 \
   --control-plane --certificate-key bd9fc1600d2db4f2b323a17b2b7be4f4234d7ed8705bc64976dcd43d929a24a8'

kubeadm join 常用参数

--apiserver-advertise-address string
如果该节点托管一个新的控制平面实例,则 API 服务器将公布其正在侦听的 IP 地址。如果未设置,则使用默认网络接口。
--apiserver-bind-port int32     默认值: 6443
如果节点应该托管新的控制平面实例,则为 API 服务器要绑定的端口。
--certificate-key string
使用此密钥可以解密由 init 上传的证书 secret。
--config string
kubeadm 配置文件的路径。
--control-plane
在此节点上创建一个新的控制平面实例
--cri-socket string
要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项。
--discovery-file string
对于基于文件的发现,给出用于加载集群信息的文件或者 URL。
--discovery-token string
对于基于令牌的发现,该令牌用于验证从 API 服务器获取的集群信息。
--discovery-token-ca-cert-hash stringSlice
对基于令牌的发现,验证根 CA 公钥是否与此哈希匹配 (格式: "<type>:<value>")。
--discovery-token-unsafe-skip-ca-verification
对于基于令牌的发现,允许在未关联 --discovery-token-ca-cert-hash 参数的情况下添加节点。
-k, --experimental-kustomize string
用于存储 kustomize 为静态 pod 清单所提供的补丁的路径。
-h, --help
join 操作的帮助命令
--ignore-preflight-errors stringSlice
错误将显示为警告的检查列表;例如:'IsPrivilegedUser,Swap'。取值为 'all' 时将忽略检查中的所有错误。
--node-name string
指定节点的名称
--skip-phases stringSlice
要跳过的阶段列表
--tls-bootstrap-token string
指定在加入节点时用于临时通过 Kubernetes 控制平面进行身份验证的令牌。
--token string
如果未提供这些值,则将它们用于 discovery-token 令牌和 tls-bootstrap 令牌。

配置 master 管理命令

ansible master -m shell -a 'echo "source <(kubectl completion bash)" >> ~/.bashrc'

ansible master -m shell -a 'mkdir -p /root/.kube'

ansible master -m copy -a 'src=/etc/kubernetes/admin.conf dest=/root/.kube/config mode=0600 owner=root remote_src=yes'

验证 master

 kubectl get nodes -l node-role.kubernetes.io/master
NAME    STATUS     ROLES    AGE     VERSION
ukm01   NotReady   master   3m26s   v1.17.3
ukm02   NotReady   master   1m56s   v1.17.3
ukm03   NotReady   master   2m14s   v1.17.3

 kubectl get pods --all-namespaces
NAMESPACE     NAME                            READY   STATUS    RESTARTS   AGE
kube-system   coredns-7f9c544f75-h9hmm        0/1     Pending   0          3m55s
kube-system   coredns-7f9c544f75-k9pb7        0/1     Pending   0          3m55s
kube-system   etcd-ukm01                      1/1     Running   1          20s
kube-system   etcd-ukm02                      1/1     Running   0          40s
kube-system   etcd-ukm03                      1/1     Running   0          20s
kube-system   kube-apiserver-ukm01            1/1     Running   0          20s
kube-system   kube-apiserver-ukm02            1/1     Running   0          20s
kube-system   kube-apiserver-ukm03            1/1     Running   0          20s
kube-system   kube-controller-manager-ukm01   1/1     Running   3          5m17s
kube-system   kube-controller-manager-ukm02   1/1     Running   0          74s
kube-system   kube-controller-manager-ukm03   1/1     Running   2          3m27s
kube-system   kube-proxy-4fkkx                1/1     Running   0          3m27s
kube-system   kube-proxy-5vjpc                1/1     Running   0          2m9s
kube-system   kube-proxy-plx2x                1/1     Running   0          3m55s
kube-system   kube-scheduler-ukm01            1/1     Running   2          5m17s
kube-system   kube-scheduler-ukm02            1/1     Running   0          75s
kube-system   kube-scheduler-ukm03            1/1     Running   0          3m26s

确认 kube-proxy 启用了 ipvs 模式

 kubectl get configmaps kube-proxy -n kube-system -o yaml
...
    iptables:
      masqueradeAll: false
      masqueradeBit: null
      minSyncPeriod: 0s
      syncPeriod: 0s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 5s
      scheduler: wlc
      strictARP: false
      syncPeriod: 30s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: ipvs
...

查看 ipvs 转发情况

 ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.96.0.1:443 wlc
  -> 10.10.34.92:8443             Masq    1      0          0
  -> 10.10.34.93:8443             Masq    1      0          0
  -> 10.10.34.94:8443             Masq    1      0          0
TCP  10.96.0.10:53 wlc
TCP  10.96.0.10:9153 wlc
UDP  10.96.0.10:53 wlc

查看网卡信息

 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether fa:16:3e:cf:28:7f brd ff:ff:ff:ff:ff:ff
    inet 10.10.34.92/24 brd 10.10.34.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fecf:287f/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:81:5a:e2:7c brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:81ff:fe5a:e27c/64 scope link
       valid_lft forever preferred_lft forever
6: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1440 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
46: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
    link/ether 6a:10:8f:81:3e:61 brd ff:ff:ff:ff:ff:ff
    inet 10.96.0.10/32 brd 10.96.0.10 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.96.0.1/32 brd 10.96.0.1 scope global kube-ipvs0
       valid_lft forever preferred_lft forever

更新 etcd 集群配置

ansible master -m shell -a 'sed -i "/--initial-cluster=/c\    - --initial-cluster=ukm01=https://10.10.34.92:2380,ukm02=https://10.10.34.93:2380,ukm03=https://10.10.34.94:2380" /etc/kubernetes/manifests/etcd.yaml'

apiserver 默认访问本地的 etcd 节点,如果需要访问集群所有节点可以修改配置。
ansible master -m shell -a 'sed -i "/- --etcd-servers/c\    - --etcd-servers=https://10.10.34.92:2379,https://10.10.34.93:2379,https://10.10.34.94:2379" /etc/kubernetes/manifests/kube-apiserver.yaml'

查看 etcd 成员状态

成员管理命令:

  • add - 添加集群成员
  • list - 查看集群成员信息
  • promote - 提升集群成员权限
  • remove - 从集群中删除成员ID
  • update - 更新集群成员信息
 kubectl exec -n kube-system -it $(kubectl get pod  -n kube-system -l component=etcd -o jsonpath='{.items[0].metadata.name}') sh

 或者下载 etcdctl
 curl -L -O https://github.com/etcd-io/etcd/releases/download/v3.4.3/etcd-v3.4.3-linux-amd64.tar.gz
 tar xzvf etcd-v3.4.3-linux-amd64.tar.gz
 mv etcd-v3.4.3-linux-amd64/etcd* /usr/local/bin/

 ETCDCTL=3 etcdctl --write-out=table \
  --cert /etc/kubernetes/pki/etcd/peer.crt \
  --key /etc/kubernetes/pki/etcd/peer.key \
  --cacert /etc/kubernetes/pki/etcd/ca.crt \
  --endpoints https://ukm01:2379,https://ukm02:2379,https://ukm03:2379 \
  member list

+------------------+---------+-------+--------------------------+--------------------------+------------+
|        ID        | STATUS  | NAME  |        PEER ADDRS        |       CLIENT ADDRS       | IS LEARNER |
+------------------+---------+-------+--------------------------+--------------------------+------------+
| 7a212ff0c04f1e82 | started | ukm02 | https://10.10.34.93:2380 | https://10.10.34.93:2379 |      false |
| ae758756c0c6b09c | started | ukm01 | https://10.10.34.92:2380 | https://10.10.34.92:2379 |      false |
| ff90415307bdc341 | started | ukm03 | https://10.10.34.94:2380 | https://10.10.34.94:2379 |      false |
+------------------+---------+-------+--------------------------+--------------------------+------------+

验证 etcd 集群状态

 ETCDCTL=3 etcdctl --cluster --write-out=table \
  --cert /etc/kubernetes/pki/etcd/peer.crt \
  --key /etc/kubernetes/pki/etcd/peer.key \
  --cacert /etc/kubernetes/pki/etcd/ca.crt \
  --endpoints https://ukm01:2379,https://ukm02:2379,https://ukm03:2379 \
  endpoint status

+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|         ENDPOINT         |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://10.10.34.94:2379 | 4677521bc1465d7e |   3.4.3 |  1.5 MB |     false |      false |         9 |       1671 |               1671 |        |
| https://10.10.34.92:2379 | ae758756c0c6b09c |   3.4.3 |  1.6 MB |     false |      false |         9 |       1671 |               1671 |        |
| https://10.10.34.93:2379 | ff3c0a769521e2c2 |   3.4.3 |  1.5 MB |      true |      false |         9 |       1671 |               1671 |        |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

查看 etcd 节点健康状况

 ETCDCTL=3 etcdctl --cluster --write-out=table \
  --cert /etc/kubernetes/pki/etcd/peer.crt \
  --key /etc/kubernetes/pki/etcd/peer.key \
  --cacert /etc/kubernetes/pki/etcd/ca.crt \
  --endpoints https://ukm01:2379,https://ukm02:2379,https://ukm03:2379 \
  endpoint health

+--------------------------+--------+-------------+-------+
|         ENDPOINT         | HEALTH |    TOOK     | ERROR |
+--------------------------+--------+-------------+-------+
| https://10.10.34.93:2379 |   true | 18.384799ms |       |
| https://10.10.34.94:2379 |   true | 18.649393ms |       |
| https://10.10.34.92:2379 |   true | 18.831792ms |       |
+--------------------------+--------+-------------+-------+

增加 node 节点

在 uki01 uki02 uki03 ukn01 ukn02 ukn03 上执行

ansible infra:worker -m shell -a 'kubeadm join 10.10.34.89:8443 \
   --token 7nf8wp.cefgemzgn5xcdmln \
   --discovery-token-ca-cert-hash sha256:36b328e0052c7f8e7cac826d70b21bef0cdc4e0505fddc8200c52b8b01605da3'

SDN

安装 calico

curl -L https://docs.projectcalico.org/manifests/calico.yaml -o calico.yaml

kubectl apply -f calico.yaml

查看服务状态

  • node 节点处于 Ready 状态
  • 每个节点上都有一个 pod:calico-node
 kubectl get nodes
NAME    STATUS   ROLES    AGE     VERSION
uki01   Ready    infra    5m      v1.17.3
uki02   Ready    infra    5m      v1.17.3
uki03   Ready    infra    5m      v1.17.3
ukm01   Ready    master   8m      v1.17.3
ukm02   Ready    master   8m      v1.17.3
ukm03   Ready    master   8m      v1.17.3
ukn01   Ready    worker   5m      v1.17.3
ukn02   Ready    worker   5m      v1.17.3
ukn03   Ready    worker   5m      v1.17.3

 watch kubectl get pods -n kube-system -o wide
NAME                                       READY   STATUS    RESTARTS   AGE   IP                NODE    NOMINATED NODE   READINESS GATES
...
calico-kube-controllers-5b644bc49c-7xjzr   1/1     Running   0          30s   192.168.144.138   uki01   <none>           <none>
calico-node-57rns                          1/1     Running   0          30s   10.10.34.98       ukn01   <none>           <none>
calico-node-6p8z7                          1/1     Running   0          30s   10.10.34.100      ukn03   <none>           <none>
calico-node-77jwm                          1/1     Running   0          30s   172.17.0.1        ukn02   <none>           <none>
calico-node-c4gxf                          1/1     Running   0          30s   10.10.34.95       uki01   <none>           <none>
calico-node-gdb5j                          1/1     Running   0          30s   10.10.34.96       uki02   <none>           <none>
calico-node-gmzmf                          1/1     Running   0          30s   10.10.34.93       ukm02   <none>           <none>
calico-node-jdd2f                          1/1     Running   0          30s   10.10.34.97       uki03   <none>           <none>
calico-node-mrr49                          1/1     Running   0          30s   10.10.34.92       ukm01   <none>           <none>
calico-node-w5b7r                          1/1     Running   0          30s   10.10.34.94       ukm03   <none>           <none>
...

 kubectl get ippool -o wide
NAME                  AGE
default-ipv4-ippool   2m

验证 calico

 下载 calicoctl
 curl -L -o /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v3.11.2/calicoctl-linux-amd64
 chmod +x /usr/local/bin/calicoctl

 使用 kubernetes api 存储数据
 mkdir -p /etc/calico
 cat > /etc/calico/calicoctl.cfg <<EOF
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  datastoreType: kubernetes
  kubeconfig: /etc/kubernetes/admin.conf   使用 admin 配置
  k8sAPIEndpoint: https://10.10.34.89:8443
  k8sCertFile: /etc/kubernetes/pki/apiserver-kubelet-client.crt
  k8sKeyFile: /etc/kubernetes/pki/apiserver-kubelet-client.key
  k8sCAFile: /etc/kubernetes/pki/ca.crt
EOF

 使用独立的 etcd 存储数据
 mkdir -p /etc/calico
 cat > /etc/calico/calicoctl.cfg <<EOF
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  datastoreType: etcdv3
  etcdEndpoints: https://10.10.34.92:2379,https://10.10.34.93:2379,https://10.10.34.94:2379
  etcdKeyFile: /etc/kubernetes/pki/etcd/peer.key
  etcdCertFile: /etc/kubernetes/pki/etcd/peer.crt
  etcdCACertFile: /etc/kubernetes/pki/etcd/ca.crt
EOF

 查看 node
 calicoctl node status
Calico process is running.

IPv4 BGP status
+--------------+-------------------+-------+------------+-------------+
| PEER ADDRESS |     PEER TYPE     | STATE |   SINCE    |    INFO     |
+--------------+-------------------+-------+------------+-------------+
| 10.10.34.95  | node-to-node mesh | up    | 2020-04-11 | Established |
| 10.10.34.96  | node-to-node mesh | up    | 2020-04-11 | Established |
| 10.10.34.97  | node-to-node mesh | up    | 2020-04-11 | Established |
| 10.10.34.93  | node-to-node mesh | up    | 2020-04-11 | Established |
| 10.10.34.94  | node-to-node mesh | up    | 2020-04-11 | Established |
| 10.10.34.98  | node-to-node mesh | up    | 2020-04-11 | Established |
| 10.10.34.99  | node-to-node mesh | up    | 2020-04-11 | Established |
| 10.10.34.100 | node-to-node mesh | up    | 2020-04-11 | Established |
+--------------+-------------------+-------+------------+-------------+

IPv6 BGP status
No IPv6 peers found.


 calicoctl get node -o wide
NAME    ASN       IPV4              IPV6
uki01   (64512)   10.10.34.95/24
uki02   (64512)   10.10.34.96/24
uki03   (64512)   10.10.34.97/24
ukm01   (64512)   10.10.34.92/24
ukm02   (64512)   10.10.34.93/24
ukm03   (64512)   10.10.34.94/24
ukn01   (64512)   10.10.34.98/24
ukn02   (64512)   10.10.34.99/24
ukn03   (64512)   10.10.34.100/24

 查看 ippool
 calicoctl get ippool -o wide
NAME                  CIDR             NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR
default-ipv4-ippool   192.168.0.0/16   true   Always     Never       false      all()

 查看 ip 状态
 calicoctl ipam show
+----------+----------------+-----------+------------+--------------+
| GROUPING |      CIDR      | IPS TOTAL | IPS IN USE |   IPS FREE   |
+----------+----------------+-----------+------------+--------------+
| IP Pool  | 192.168.0.0/16 |     65536 | 5  (0%)    | 65531 (100%) |
+----------+----------------+-----------+------------+--------------+

 查看已分配的服务节点信息
 calicoctl get workloadendpoints -o wide -n kube-system
NAMESPACE     NAME                                                          WORKLOAD                                   NODE    NETWORKS             INTERFACE         PROFILES                                                  NATS
kube-system   ukn02-k8s-calico--kube--controllers--75d56dfc47--xfdp9-eth0   calico-kube-controllers-75d56dfc47-xfdp9   ukn02   192.168.33.65/32     calif1d8798ea15   kns.kube-system,ksa.kube-system.calico-kube-controllers
kube-system   uki02-k8s-coredns--546565776c--mkx9n-eth0                     coredns-546565776c-mkx9n                   uki02   192.168.225.1/32     calib399f7859db   kns.kube-system,ksa.kube-system.coredns
kube-system   ukn03-k8s-coredns--546565776c--v9wgw-eth0                     coredns-546565776c-v9wgw                   ukn03   192.168.188.129/32   cali4fffc74a7b2   kns.kube-system,ksa.kube-system.coredns

calico 网络资源

官方文档: https://docs.projectcalico.org/reference/resources/overview

  • BGPConfiguration
---
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
  name: default
spec:
  logSeverityScreen: Info
  nodeToNodeMeshEnabled: true
  asNumber: 63400
  serviceClusterIPs:
  - cidr: 10.96.0.0/12
  serviceExternalIPs:
  - cidr: 104.244.42.129/32
  - cidr: 172.217.3.0/24
  • BGPPeer
---
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
  name: some.name
spec:
  node: rack1-host1
  peerIP: 192.168.1.1
  asNumber: 63400
  • FelixConfiguration
---
apiVersion: projectcalico.org/v3
kind: FelixConfiguration
metadata:
  name: default
spec:
  ipv6Support: false
  ipipMTU: 1400
  chainInsertMode: Append
  • GlobalNetworkPolicy
---
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: allow-tcp-6379
spec:
  selector: role == 'database'
  types:
  - Ingress
  - Egress
  ingress:
  - action: Allow
    metadata:
      annotations:
        from: frontend
        to: database
    protocol: TCP
    source:
      selector: role == 'frontend'
    destination:
      ports:
      - 6379
  egress:
  - action: Allow
  • GlobalNetworkSet
---
apiVersion: projectcalico.org/v3
kind: GlobalNetworkSet
metadata:
  name: a-name-for-the-set
  labels:
    role: external-database
spec:
  nets:
  - 198.51.100.0/28
  - 203.0.113.0/24
  • HostEndpoint
---
apiVersion: projectcalico.org/v3
kind: HostEndpoint
metadata:
  name: some.name
  labels:
    type: production
spec:
  interfaceName: eth0
  node: myhost
  expectedIPs:
  - 192.168.0.1
  - 192.168.0.2
  profiles:
  - profile1
  - profile2
  ports:
  - name: some-port
    port: 1234
    protocol: TCP
  - name: another-port
    port: 5432
    protocol: UDP
  • IPPool
---
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: my.ippool-1
spec:
  cidr: 10.1.0.0/16
  ipipMode: CrossSubnet
  natOutgoing: true
  disabled: false
  nodeSelector: all()
  • NetworkPolicy
---
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-tcp-6379
  namespace: production
spec:
  selector: role == 'database'
  types:
  - Ingress
  - Egress
  ingress:
  - action: Allow
    metadata:
      annotations:
        from: frontend
        to: database
    protocol: TCP
    source:
      selector: role == 'frontend'
    destination:
      ports:
      - 6379
  egress:
  - action: Allow
  • NetworkSet
---
apiVersion: projectcalico.org/v3
kind: NetworkSet
metadata:
  name: external-database
  namespace: staging
  labels:
    role: db
spec:
  nets:
  - 198.51.100.0/28
  - 203.0.113.0/24
  • Node
---
apiVersion: projectcalico.org/v3
kind: Node
metadata:
  name: node-hostname
spec:
  bgp:
    asNumber: 64512
    ipv4Address: 10.244.0.1/24
    ipv6Address: 2001:db8:85a3::8a2e:370:7334/120
    ipv4IPIPTunnelAddr: 192.168.0.1
  • Profile
---
apiVersion: projectcalico.org/v3
kind: Profile
metadata:
  name: dev-apps
spec:
  ingress:
  - action: Deny
    source:
      nets:
      - 10.0.20.0/24
  - action: Allow
    source:
      selector: stage == 'development'
  egress:
  - action: Allow
  labelsToApply:
    stage: development
  • WorkloadEndpoint
---
apiVersion: projectcalico.org/v3
kind: WorkloadEndpoint
metadata:
  name: node1-k8s-my--nginx--b1337a-eth0
  namespace: default
  labels:
    app: frontend
    projectcalico.org/namespace: default
    projectcalico.org/orchestrator: k8s
spec:
  node: node1
  orchestrator: k8s
  endpoint: eth0
  containerID: 1337495556942031415926535
  pod: my-nginx-b1337a
  endpoint: eth0
  interfaceName: cali0ef24ba
  mac: ca:fe:1d:52:bb:e9
  ipNetworks:
  - 192.168.0.0/32
  profiles:
  - profile1
  ports:
  - name: some-port
    port: 1234
    protocol: TCP
  - name: another-port
    port: 5432
    protocol: UDP

卸载 calico

kubectl delete -f calico.yaml

删除 calico 配置

ansible ins -m shell -a 'rm -rf /etc/cni /opt/cni/ /var/lib/calico/'

集群校验

查看集群信息

 kubectl config get-clusters
NAME
shenzhen

 kubectl cluster-info
Kubernetes master is running at https://10.10.34.89:8443
KubeDNS is running at https://10.10.34.89:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

查看 namespace

 kubectl get namespaces
NAME              STATUS   AGE
default           Active   15m
kube-node-lease   Active   15m
kube-public       Active   15m
kube-system       Active   15m

查看节点状态

 kubectl get nodes
NAME    STATUS     ROLES    AGE    VERSION
uki01   NotReady   <none>   7m     v1.17.3
uki02   NotReady   <none>   7m    v1.17.3
uki03   NotReady   <none>   7m    v1.17.3
ukm01   NotReady   master   10m    v1.17.3
ukm02   NotReady   master   14m    v1.17.3
ukm03   NotReady   master   13m    v1.17.3
ukn01   NotReady   <none>   7m     v1.17.3
ukn02   NotReady   <none>   7m     v1.17.3
ukn03   NotReady   <none>   7m     v1.17.3

添加 infra 标签

 kubectl label node uki01 uki02 uki03 node-role.kubernetes.io/infra=true
node/uki01 labeled
node/uki02 labeled
node/uki03 labeled

 kubectl get nodes -l node-role.kubernetes.io/infra
NAME    STATUS      ROLES   AGE   VERSION
uki01   NotReady    infra   8m    v1.17.3
uki02   NotReady    infra   8m    v1.17.3
uki03   NotReady    infra   8m    v1.17.3

添加 worker 标签

 kubectl label node ukn01 ukn02 ukn03 node-role.kubernetes.io/worker=true
node/ukn01 labeled
node/ukn02 labeled
node/ukn03 labeled

 kubectl get nodes -l node-role.kubernetes.io/worker
NAME    STATUS      ROLES    AGE   VERSION
ukn01   NotReady    worker   8m    v1.17.3
ukn02   NotReady    worker   8m    v1.17.3
ukn03   NotReady    worker   8m    v1.17.3

查看所有节点标签

 kubectl get nodes --show-labels
NAME    STATUS     ROLES    AGE     VERSION   LABELS
uki01   NotReady   infra    10m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=uki01,kubernetes.io/os=linux,node-role.kubernetes.io/infra=true
uki02   NotReady   infra    10m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=uki02,kubernetes.io/os=linux,node-role.kubernetes.io/infra=true
uki03   NotReady   infra    10m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=uki03,kubernetes.io/os=linux,node-role.kubernetes.io/infra=true
ukm01   NotReady   master   19m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=ukm01,kubernetes.io/os=linux,node-role.kubernetes.io/master=
ukm02   NotReady   master   17m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=ukm02,kubernetes.io/os=linux,node-role.kubernetes.io/master=
ukm03   NotReady   master   15m      v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=ukm03,kubernetes.io/os=linux,node-role.kubernetes.io/master=
ukn01   NotReady   worker   10m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=ukn01,kubernetes.io/os=linux,node-role.kubernetes.io/worker=true
ukn02   NotReady   worker   10m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=ukn02,kubernetes.io/os=linux,node-role.kubernetes.io/worker=true
ukn03   NotReady   worker   10m     v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=ukn03,kubernetes.io/os=linux,node-role.kubernetes.io/worker=true

删除节点标签

kubectl label node uki01 uki02 uki03 node-role.kubernetes.io/infra-

kubectl 简介

基础命令:
  create        从文件或 stdin 创建资源
  expose        为 deployment、pod 创建 Service
  run           使用 image 去创建一个服务
  set           更新resource ,比如更新env环境变量,image,resources 资源限制,selector  subject等。

管理命令:
  explain       查看资源定义(文档)。如 kubectl explain replicaset
  get           最基本的对象查询命令。如 kubectl get nodes/pods/deploy/rs/ns/secret等等, 加-o wide查看详细信息,-o yaml 或-o json 输出具体格式。
  edit          编辑资源配置,完成对象的更新。
  delete        删除指定资源,支持文件名、资源名、label selector。

部署命令:
  rollout       Deployment, Daemonset的升级过程管理(查看状态status、操作历史history、暂停升级、恢复升级、回滚等)
  scale         修改Deployment, ReplicaSet, Replication Controller, Job的实例数,实现一个副本集的手工扩展
  autoscale     为Deploy, RS, RC配置自动伸缩规则(依赖heapster和hpa)

集群管理命令:
  certificate   修改证书资源
  cluster-info  查看集群信息
  top           查看资源占用率 (CPU/Memory/Storage)
  cordon        标记节点为不可调度状态
  uncordon      标记节点为可调度状态
  drain         驱逐节点上的 pod ,准备下线维护
  taint         设置节点污点隔离标记

故障诊断命令:
  describe      查看资源详情
  logs          查看 pod 内容器的日志
  attach        Attach 到 pod 内的一个容器
  exec          进入指定容器执行命令
  port-forward  为 pod 创建本地端口映射
  proxy         为 Kubernetes API server 创建代理
  cp            容器内外/容器间文件拷贝
  auth          授权校验

高级命令:
  diff          比较当前版本和要部署的版本
  apply         从文件或stdin创建/更新资源
  patch         使用strategic merge patch语法更新对象的某些字段
  replace       从文件或stdin更新资源
  wait          实验功能:等待一种或多种资源的特定条件。
  convert       在不同API版本之间转换对象定义
  kustomize     从指定目录或远程URL构建Kustomization目标。

配置命令:
  label         给资源设置label
  annotate      给资源设置annotation
  completion    获取shell自动补全脚本 (bash or zsh)

其他命令:
  alpha         Alpha中功能的命令
  api-resources 打印当前 kubernetes API 所支持的命令资源
  api-versions  打印当前 kubernetes API 所支持的 api 接口以及版本信息
  config        修改kubectl配置(kubeconfig文件),如context。
  plugin        提供用于与插件交互的插件程序。
  version       打印当前 kubernetes 的服务端和客户端版本

调度策略 Scheduling Policies

kube-scheduler 给一个 pod 做调度选择包含两个步骤:

  • 过滤 Filtering
    过滤策略会检查候选 Node 是否满足 Pod 的创建需求;
    在过滤之后得出一个 Node 列表,里面包含了所有可调度节点;
    如果为空,代表这个 Pod 不可调度。

  • 打分 Scoring
    根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。

过滤策略

  • PodFitsHostPorts:检查 Pod 请求的端口是否空闲(网络协议类型)。
  • PodFitsHost:检查 Pod 是否通过其主机名指定了特定的 Node。
  • PodFitsResources:检查节点空闲资源(例如 CPU 和内存)是否满足 Pod 的要求。
  • PodMatchNodeSelector:检查 Pod label 是否与 Node label 匹配。
  • NoVolumeZoneConflict:检查 Volume 存储卷是否可用。
  • NoDiskConflict:检查节点 Disk 磁盘是否冲突。
  • MaxCSIVolumeCount:检查节点挂载的 CSI 卷是否超出最大限制。
  • CheckNodeMemoryPressure:节点正在报告内存压力,并且没有配置的异常,则不会在此处安排 Pod。
  • CheckNodePIDPressure:节点正在报告进程 PID 稀缺,并且没有配置的异常,则不会在此处安排 Pod。
  • CheckNodeDiskPressure:节点正在报告存储压力,并且没有配置的异常,则不会在此处安排Pod。
  • CheckNodeCondition:检查节点的文件系统、网络状态或者 kubelet 是否准备好运行 Pod。
  • PodToleratesNodeTaints:检查 Pod 的 Tolerates 是否可以容忍节点的 Taints。
  • CheckVolumeBinding:检查 PVC 状态是否满足 Pod 创建需求。

打分策略

  • SelectorSpreadPriority:将属于同一 StatefulSet、 ReplicaSet 或 Service 的 Pod 分散在不同的主机 。
  • InterPodAffinityPriority:根据 Pod 亲和条目打分,匹配到给定节点的条目权重相加,结果值越大的节点得分越高。
  • LeastRequestedPriority:计算Pods需要的CPU和内存在当前节点可用资源的百分比,具有最小百分比的节点就是最优。
  • MostRequestedPriority:适用动态伸缩集群环境,会优先调度pod到使用率最高的主机节点。当伸缩集群时,就会腾出空闲机器,从而可以停机处理。
  • RequestedToCapacityRatioPriority:为节点上每个资源占用比例设定得分值,给资源打分函数在打分时使用。
  • BalancedResourceAllocation:优选那些使得资源利用率更为均衡的节点。
  • NodePreferAvoidPodsPriority:根据节点是否包含 scheduler.alpha.kubernetes.io/preferAvoidPods 来计算其优先级,将两个不同 Pod 运行在不同的节点上。
  • NodeAffinityPriority:基于 PreferredDuringSchedulingIgnoredDuringExecution 来进行节点亲和调度。
  • TaintTolerationPriority:基于 Pod 中对节点的污点容忍程度进行优先级评估,这个策略能够调整待选节点的排名。
  • ImageLocalityPriority:已经拥有 Pod 需要的 image 的节点会有较高的优先级。
  • ServiceSpreadingPriority:确保归属于同一给 Service 的 Pod 调度到不同的节点上,确保节点宕机之后 Service 也具有很强容灾能力。
  • EqualPriority:将所有的 Node 设置成相同的权重为 1。
  • EvenPodsSpreadPriority:实现首选的Pod拓扑扩展约束。

调度配置 Scheduling Profiles

官方文档 https://kubernetes.io/docs/concepts/scheduling-eviction/scheduling-framework/

每次调度一个Pod的尝试都分为两个阶段,调度周期 Scheduling Cycle 和 绑定周期 Binding Cycle。

  • 调度周期为Pod选择一个节点,并且绑定周期将该决定应用于集群。调度周期和绑定周期一起被称为“调度上下文”。
  • 调度周期是串行运行的,而绑定周期可能是同时运行的。
  • 如果确定Pod不可调度或存在内部错误,则可以中止调度或绑定周期。Pod将返回队列并重试。

扩展点 Extension points

QueueSort - 对 Pod 的待调度队列进行排序,比较两个 Pod 谁更优先调度,同一时间点只能有一个 QueueSort 插件生效。

调度周期 Scheduling Cycle

  • PreFilter - 对 Pod 条件信息进行预处理,如果 PreFilter 返回了 error 则调度过程终止。
  • Filter - 标记不符合调度条件的
  • PreScore - 对 Pod 进行预评分,为 Score 插件使用提供可共享的状态。如果PreScore插件返回错误,则调度周期将中止。
  • Score - 对符合过滤条件的节点进行计分排名,在 NormalizeScore 阶段之后,调度程序将根据权重合并所有的节点分值。
  • NormalizeScore - 在调度程序计算节点的最终排名之前修改分数。
  • Reserve - 在符合条件的节点上为 Pod 保留资源。
  • Permit - 用于阻止或者延迟 Pod 与节点的绑定。
    • approve - 批准
    • deny - 拒绝
    • wait - 等待

绑定周期 Binding Cycle

  • PreBind - 用于执行绑定 Pod 之前所需的任何工作。如果任何 PreBind 插件返回错误,则 Pod 被拒绝并返回到调度队列。
  • Bind - 用于 Pod 绑定。如果绑定插件选择处理 Pod,则会跳过其余的绑定插件。
  • PostBind - 成功绑定Pod后,将调用后绑定插件。绑定周期到此结束,可以用来清理关联的资源。

Unreserve - 如果节点为 Pod 预留了资源,Pod 又在被绑定过程中被拒绝绑定,则执行 unreserve 释放为 Pod 预留的资源。

调度插件 Scheduling plugins

默认情况下启用以下插件,实现这些扩展点中的一个或多个:

  • DefaultTopologySpread:基于 Service、ReplicaSets 和 StatefulSets 分散部署。扩展点:PreScore, Score。
  • ImageLocality:倾向于已经具有 Pod 运行的 image 的节点。扩展点:Score。
  • TaintToleration:实施污点和宽容。扩展点:Filter,Prescore,Score。
  • NodeName:Pod 配置的节点与节点是否匹配。扩展点:Filter。
  • NodePorts:节点端口是否被占用。扩展点:PreFilter,Filter。
  • NodePreferAvoidPods:根据节点 annotation 进行评分 scheduler.alpha.kubernetes.io/preferAvoidPods。扩展点:Score。
  • NodeAffinity:节点的亲和与反亲和。扩展点:Filter,Score。
  • PodTopologySpread:实现 Pod 拓扑传播。扩展点:PreFilter,Filter,PreScore,Score。
  • NodeUnschedulable:过滤掉 .spec.unschedulable 为 true 的节点。扩展点:Filter。
  • NodeResourcesFit:检查节点是否具有 Pod 请求的资源。扩展点:PreFilter,Filter。
  • NodeResourcesBallancedAllocation:使用资源利用均衡的节点。扩展点:Score。
  • NodeResourcesLeastAllocated:使用资源分配少的节点。扩展点:Score。
  • VolumeBinding:节点是否具有或可以绑定所请求卷。扩展点:Filter。
  • VolumeRestrictions:节点挂载的卷是否满足限制条件。扩展点:Filter。
  • VolumeZone:检查卷是否满足任何区域要求。扩展点:Filter。
  • NodeVolumeLimits:检查节点是否可以符合 CSI 限制。扩展点:Filter。
  • EBSLimits:检查节点是否满足 AWS EBS 限制。扩展点:Filter。
  • GCEPDLimits:检查节点是否满足 GCP-PD 限制。扩展点:Filter。
  • AzureDiskLimits:检查节点是否满足 Azure Disk 限制。扩展点:Filter。
  • InterPodAffinity:基于 Pod 亲和与反亲和。扩展点:PreFilter,Filter,PreScore,Score。
  • PrioritySort:基于默认优先级的排序。扩展点:QueueSort。
  • DefaultBinder:基于默认的绑定机制。扩展点:Bind。

您还可以通过组件配置API启用以下默认未启用的插件:

  • NodeResourcesMostAllocated:倾向于资源分配高的节点。扩展点:Score。
  • RequestedToCapacityRatio:基于节点的资源可用性比例。扩展点:Score。
  • NodeResourceLimits:支持满足 Pod 资源限制的节点。扩展点:PreScore,Score。
  • CinderVolume:检查节点是否可以满足 OpenStack Cinder 限制。扩展点:Filter。
  • NodeLabel:根据节点的 label 进行评分。扩展点:Filter,Score。
  • ServiceAffinity:检查 Service label 匹配的节点,该插件有利于在节点之间部署服务。扩展点:PreFilter,Filter,Score。

亲和 Affinity 与 反亲和 Anti-Affinity

亲和规则

  • requiredDuringSchedulingRequiredDuringExecution
    该规则还未正式上线;
    在调度期间必须满足亲和或者反亲和规则,如果不能满足规则,则 pod 不能被调度到对应的主机上;
    在之后的运行过程中,系统会持续监规则是否满足。

  • RequiredDuringSchedulingIgnoredDuringExecution
    在调度期间必须满足亲和或者反亲和规则,如果不能满足规则,则 pod 不能被调度到对应的主机上;
    在之后的运行过程中,系统不再检查这些规则是否满足。

  • PreferredDuringSchedulingIgnoredDuringExecution
    在调度期间尽量满足亲和或者反亲和规则,如果不能满足规则,pod 也有可能被调度到对应的主机上;
    在之后的运行过程中,系统不再检查这些规则是否满足。

nodeAffinity

nodeAffinity - 节点亲和,使用场景 :

  • 将服务的所有Pod部署到指定的符合标签规则的主机上。
  • 将服务的所有Pod部署到除部分主机外的其他主机上。
  • 支持的操作符: In,NotIn,Exists,DoesNotExist,Gt,Lt。

节点亲和:

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: another-node-label-key
            operator: In
            values:
            - another-node-label-value
  containers:
  - name: with-node-affinity
    image: k8s.gcr.io/pause:2.0

podAffinity 与 podAntiAffinity

注意:
Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度。我们不建议在超过数百个节点的集群中使用它们。

podAffinity - pod 亲和,使用场景 :

  • 将某一特定的 pod 部署在同一拓扑域中,不用指定具体的拓扑域。
  • 为了减少关联的2个服务之间的网络延迟(或其它原因),将他们部署在同一拓扑域中。
  • 支持的操作符: In,NotIn,Exists,DoesNotExist。

podAntiAffinity - pod 反亲和,使用场景 :

  • 将一个服务的 pod 分散在不同的主机或者拓扑域中,提高服务本身的稳定性。
  • 为某一个 pod 提供节点的资源独占权限。
  • 把可能会相互影响的 pod 分散在不同的主机上。
  • 支持的操作符: In,NotIn,Exists,DoesNotExist。

pod 亲和与反亲和:

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: failure-domain.beta.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

污点驱逐 Taint

  • NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上
  • PreferNoSchedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上
  • NoExecute:表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去
删除污点,开启 master 节点 pod 调度功能。
kubectl taint node ukm03 node-role.kubernetes.io/master=:NoSchedule-

添加污点,关闭 master 节点 pod 调度功能。
kubectl taint node ukm03 node-role.kubernetes.io/master=:NoSchedule

容忍 Toleration

设置了污点的节点,Pod 将在一定程度上不会被调度到节点上。 通过设置 pod 容忍(Toleration),将 pod 调度到存在污点的Node上。通过在Pod的spec中设置tolerations字段,给Pod设置上容忍点:

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
  tolerationSeconds: 3600
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
- key: "key2"
  operator: "Exists"
  effect: "NoSchedule"
  • key、vaule、effect要与Node上设置的taint保持一致。
  • 当不指定key值时,表示容忍所有的污点key;当不指定effect值时,表示容忍所有的污点作用。
  • operator的值为Exists将会忽略value值。
  • tolerationSeconds用于描述当Pod需要被驱逐时可以在Pod上继续保留运行的时间。

create 和 apply

kubectl create 命令可创建新资源。 因此再次运行该命令,则会抛出错误,因为资源名称在名称空间中应该是唯一的。

 kubectl create -f test.yml
pod/myapp-pod created

 kubectl create -f test.yml
Error from server (AlreadyExists): error when creating "pod.xml": pods "myapp-pod" already exists

kubectl apply 命令将配置应用于资源。 如果资源不在那里,那么它将被创建。 apply 命令可以二次运行,因为它只是应用配置。 在这种情况下,配置没有改变, 所以 pod 没有改变。

 kubectl apply -f test.yml
pod/myapp-pod created

 kubectl apply -f test.yml
pod/myapp-pod unchanged

kubernetes 控制器

ReplicationController

  • 确保在任何时候都有特定数量的 pod 副本处于运行状态;
  • 类似于进程管理器, ReplicationController 监控跨多个节点的多个 pod;
  • 通常缩写为 rc ,通过 replicas 控制副本的数量。
---
apiVersion: apps/v1
kind: ReplicationController
metadata:
...

ReplicaSet

  • ReplicaSet 是下一代的 ReplicationController;
  • ReplicaSet 和 ReplicationController 的唯一区别是选择器的支持,ReplicaSet 支持新的基于集合的选择器需求,而 Replication Controller 仅支持基于相等选择器的需求。
  • 通常缩写为 rs 。
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
...

Deployment

  • Deployment 管理和描述 Pods 和 ReplicaSets 部署方式;
  • 清理较旧的、不再需要的 ReplicaSets 。
  • 如果 Deployment 的当前状态不稳定,回滚到较早的 Deployment 版本。
---
apiVersion: apps/v1
kind: Deployment
metadata:
...

StatefulSet

  • 是用来管理有状态应用的对象;
  • 稳定的、唯一的网络标识符;
  • 稳定的、持久的存储;
  • 有序的、优雅的部署和缩放;
  • 有序的、自动的滚动更新。
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
...

DaemonSet

  • DaemonSet 确保全部或者某个 label 的节点上运行一个 Pod 的实例;
  • 在每个节点上运行集群存储 DaemonSet,例如 glusterd、ceph;
  • 在每个节点上运行日志收集 DaemonSet,例如 fluentd、logstash;
  • 在每个节点上运行监控 DaemonSet,例如 Prometheus Node Exporter;
  • 在每个 infra 节点上面运行一个 ingress 服务。
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
...

Job

  • Job负责处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束;
  • 运行示例作业
  • 编写工作规范
  • 处理Pod和容器故障
  • 作业终止和清理
  • 自动清理完成的作业
  • CronJob
---
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

CronJob

  • 执行基于时间调度的任务,类似于 linux 系统的 crontab 任务。
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

备份 images

 cat images.sh
!/bin/bash

imagePath="/root/images"
mkdir -p ${imagePath}

save_images() {
    docker images|awk '!/REPOSITORY/ && !/<none>/ && !/docker-registry.default.svc/ && !/jenkins/{print $1,$2}' > /tmp/images.list
    while read Name Version
    do
        fileName=$(echo $Name | awk -F\/ '{print $NF}')
        if [ ! -f "${imagePath}/${fileName}_${Version}.tgz" ];then
            echo "save image $Name:$Version"
            docker save $Name:$Version | gzip > ${imagePath}/${fileName}_${Version}.tgz
        fi
    done < /tmp/images.list
}

load_images() {
    for images in $(ls ${imagePath}/*.tgz)
    do
        echo "load image $images"
        docker load < $images
    done
}

push_images() {
    newRegistry="https://docker-registry-default.pase-hrx-stg1.zhi-niao.com/"

    docker images|awk '!/REPOSITORY/ && !/<none>/{print $1,$2}' > /tmp/images.list
    while read Name Version
    do
        fileName=$(echo $Name | awk -F/ 'sub($1,"")')
        echo "${Name}:${Version} | new tag | ${newRegistry}${fileName}:${Version}"
        docker tag ${Name}:${Version} ${newRegistry}${fileName}:${Version}
        docker push ${newRegistry}${fileName}:${Version}
        docker rmi ${newRegistry}${fileName}:${Version}
    done < /tmp/images.list
}

case $1 in
    save|s)
        save_images
        ;;
    load|l)
        load_images
        ;;
    push|p)
        push_images
        ;;
    *)
        echo "Usage: $0 {save|load}"
        ;;
esac

 分发 images.sh
 ansible master:worker:infra -m copy -a 'src=images.sh dest=/root/images.sh mode=0755'

 ansible master:worker:infra -m shell -a './images.sh save'
 for host in ukm02 ukm03 uki01 uki02 uki03 ukn01 ukn02 ukn03;do rsync -vzrtopg --progress -e ssh ${host}:/root/images/* /root/images/;done

切换 namespace

kubectl config set-context --current --namespace=kube-system

获取加入集群 token

 kubeadm token list
TOKEN                     TTL         EXPIRES                     USAGES                   DESCRIPTION                                                EXTRA GROUPS
gnc91d.aav2px3kb3021uxl   8h          2020-02-20T20:20:00+08:00   authentication,signing   The default bootstrap token generated by 'kubeadm init'.   system:bootstrappers:kubeadm:default-node-token

获取加入集群 token hash

 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
ae56bc3c9cabaaf04878be16436348419a0772342d5cc71c371fb5a79157b5a8

重新生成 kubeadm-certs

  • kubeadm-certs 密钥和解密密钥会在两个小时后失效
 kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
4379fa5fdc142d5e98d01a290b8490fc9a169e2a4c3a94695ec3745573b22fb3

查看 kubernetes 证书状态

 kubeadm alpha certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'

CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Apr 22, 2021 09:03 UTC   364d                                    no
apiserver                  Apr 22, 2021 09:03 UTC   364d            ca                      no
apiserver-etcd-client      Apr 22, 2021 09:03 UTC   364d            etcd-ca                 no
apiserver-kubelet-client   Apr 22, 2021 09:03 UTC   364d            ca                      no
controller-manager.conf    Apr 22, 2021 09:03 UTC   364d                                    no
etcd-healthcheck-client    Apr 22, 2021 09:03 UTC   364d            etcd-ca                 no
etcd-peer                  Apr 22, 2021 09:03 UTC   364d            etcd-ca                 no
etcd-server                Apr 22, 2021 09:03 UTC   364d            etcd-ca                 no
front-proxy-client         Apr 22, 2021 09:03 UTC   364d            front-proxy-ca          no
scheduler.conf             Apr 22, 2021 09:03 UTC   364d                                    no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Apr 14, 2030 11:18 UTC   9y              no
etcd-ca                 Apr 14, 2030 11:18 UTC   9y              no
front-proxy-ca          Apr 14, 2030 11:18 UTC   9y              no

重新签发所有 kubernetes 证书

 kubeadm alpha certs renew all
[renew] Reading configuration from the cluster...
[renew] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'

certificate embedded in the kubeconfig file for the admin to use and for kubeadm itself renewed
certificate for serving the Kubernetes API renewed
certificate the apiserver uses to access etcd renewed
certificate for the API server to connect to kubelet renewed
certificate embedded in the kubeconfig file for the controller manager to use renewed
certificate for liveness probes to healthcheck etcd renewed
certificate for etcd nodes to communicate with each other renewed
certificate for serving etcd renewed
certificate for the front proxy client renewed
certificate embedded in the kubeconfig file for the scheduler manager to use renewed

更新证书签名

 创建更新配置
 cat > ca-sign.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
apiServer:
  certSANs:
  - "10.10.34.89"
  - "10.10.34.92"
  - "10.10.34.93"
  - "10.10.34.94"
  - "113.108.71.77"
  - "kubernetes"
  - "kubernetes.default"
  - "kubernetes.default.svc"
  - "kubernetes.default.svc.cluster"
  - "kubernetes.default.svc.cluster.local"
controllerManager:
  extraArgs:
    cluster-signing-cert-file: /etc/kubernetes/pki/ca.crt
    cluster-signing-key-file: /etc/kubernetes/pki/ca.key
EOF

 更新 kubernetes 配置
 kubeadm config upload from-file --config=ca-sign.yaml

 确认更新配置生效
 kubeadm config view
apiServer:
  certSANs:
  - 10.10.34.89
  - 10.10.34.92
  - 10.10.34.93
  - 10.10.34.94
  - 113.108.71.77
  - kubernetes
  - kubernetes.default
  - kubernetes.default.svc
  - kubernetes.default.svc.cluster
  - kubernetes.default.svc.cluster.local
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager:
  extraArgs:
    cluster-signing-cert-file: /etc/kubernetes/pki/ca.crt
    cluster-signing-key-file: /etc/kubernetes/pki/ca.key
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.18.2
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
scheduler: {}

 删除原 apiserver 证书
 rm -rf /etc/kubernetes/pki/apiserver.*

 重新生成 apiserver 证书
 kubeadm init phase certs apiserver --config=ca-sign.yaml
W0429 15:59:26.534066   10196 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [ukm01 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local ukm01 ukm02 ukm03 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.10.34.92 10.10.34.89 10.10.34.92 10.10.34.93 10.10.34.94 113.108.71.77]


 确认 apiserver 证书更新情况
 openssl x509 -text -noout -in /etc/kubernetes/pki/apiserver.crt
...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 Subject Alternative Name:
                DNS:ukm01, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:ukm01, DNS:ukm02, DNS:ukm03, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster, DNS:kubernetes.default.svc.cluster.local, IP Address:10.96.0.1, IP Address:10.10.34.92, IP Address:10.10.34.89, IP Address:10.10.34.92, IP Address:10.10.34.93, IP Address:10.10.34.94, IP Address:113.108.71.77
...

 更新所有证书
 kubeadm alpha certs renew all --config=ca-sign.yaml
W0429 15:50:57.792294    2944 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
certificate embedded in the kubeconfig file for the admin to use and for kubeadm itself renewed
certificate for serving the Kubernetes API renewed
certificate the apiserver uses to access etcd renewed
certificate for the API server to connect to kubelet renewed
certificate embedded in the kubeconfig file for the controller manager to use renewed
certificate for liveness probes to healthcheck etcd renewed
certificate for etcd nodes to communicate with each other renewed
certificate for serving etcd renewed
certificate for the front proxy client renewed
certificate embedded in the kubeconfig file for the scheduler manager to use renewed

 通过 api 更新所有证书,需要执行确认命令。
 kubeadm alpha certs renew all --use-api --config=ca-sign.yaml &
...
[certs] Certificate request "kubeadm-cert-kubernetes-admin-8pvf8" created
...

 批准更新
 kubectl get csr | awk '!/Approved/ && !/NAME/{print "kubectl certificate approve "$1}' | bash
...
certificatesigningrequest.certificates.k8s.io/kubeadm-cert-kubernetes-admin-8pvf8 approved
...

 查看证书更新状态
 kubectl get csr
NAME                                                AGE     SIGNERNAME                     REQUESTOR          CONDITION
kubeadm-cert-front-proxy-client-tq62p               101s    kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-kube-apiserver-etcd-client-rnnjn       2m15s   kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-kube-apiserver-fk62g                   2m16s   kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-kube-apiserver-kubelet-client-5cmpv    2m11s   kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-kube-etcd-healthcheck-client-7lcw9     118s    kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-kubernetes-admin-8pvf8                 3m24s   kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-system:kube-controller-manager-bgsmt   2m8s    kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-system:kube-scheduler-dhj6b            96s     kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-ukm01-2bwbg                            115s    kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued
kubeadm-cert-ukm01-ftrgn                            104s    kubernetes.io/legacy-unknown   kubernetes-admin   Approved,Issued

卸载 kubernetes 集群

先隔离再删除节点

kubectl drain uki01 uki02 uki03 ukm01 ukm02 ukm03 ukn01 ukn02 ukn03 --delete-local-data --force --ignore-daemonsets

kubectl delete node uki01 uki02 uki03 ukm01 ukm02 ukm03 ukn01 ukn02 ukn03

重置节点状态

ansible ins -m shell -a 'kubeadm reset --force'

ansible ins -m shell -a 'rm -rf /etc/cni /opt/cni/ /var/lib/calico/ ~/.kube/'

kubernetes 集群升级

检查 kubeadm 可用版本

apt update && apt-cache policy kubeadm

升级 kubeadm

建议一台一台升级,批量操作存在无法预估的错误。

apt-mark unhold kubeadm && \
 apt-get update && apt-get install -y kubeadm=1.18.0-00 && \
 apt-mark hold kubeadm

或者
apt-get update && \
 apt-get install -y --allow-change-held-packages kubeadm=1.18.0-00

验证 kubeadm 版本

 kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:56:30Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}

隔离 ukm01

 kubectl drain ukm01 --ignore-daemonsets
node/ukm01 cordoned
node/ukm01 drained

查看可升级版本

 kubeadm upgrade plan
[upgrade/config] Making sure the configuration is correct:
[upgrade/config] Reading configuration from the cluster...
[upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[preflight] Running pre-flight checks.
[upgrade] Running cluster health checks
[upgrade] Fetching available versions to upgrade to
[upgrade/versions] Cluster version: v1.17.3
[upgrade/versions] kubeadm version: v1.18.0
[upgrade/versions] Latest stable version: v1.18.0
[upgrade/versions] Latest stable version: v1.18.0
[upgrade/versions] Latest version in the v1.17 series: v1.17.4
[upgrade/versions] Latest version in the v1.17 series: v1.17.4

Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT   CURRENT       AVAILABLE
Kubelet     9 x v1.17.3   v1.17.4

Upgrade to the latest version in the v1.17 series:

COMPONENT            CURRENT   AVAILABLE
API Server           v1.17.3   v1.17.4
Controller Manager   v1.17.3   v1.17.4
Scheduler            v1.17.3   v1.17.4
Kube Proxy           v1.17.3   v1.17.4
CoreDNS              1.6.5     1.6.7
Etcd                 3.4.3     3.4.3-0

You can now apply the upgrade by executing the following command:

  kubeadm upgrade apply v1.17.4

_____________________________________________________________________

Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT   CURRENT       AVAILABLE
Kubelet     9 x v1.17.3   v1.18.0

Upgrade to the latest stable version:

COMPONENT            CURRENT   AVAILABLE
API Server           v1.17.3   v1.18.0
Controller Manager   v1.17.3   v1.18.0
Scheduler            v1.17.3   v1.18.0
Kube Proxy           v1.17.3   v1.18.0
CoreDNS              1.6.5     1.6.7
Etcd                 3.4.3     3.4.3-0

You can now apply the upgrade by executing the following command:

  kubeadm upgrade apply v1.18.0

_____________________________________________________________________

升级 kubernetes

 kubeadm upgrade apply v1.18.0
[upgrade/config] Making sure the configuration is correct:
[upgrade/config] Reading configuration from the cluster...
[upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[preflight] Running pre-flight checks.
[upgrade] Running cluster health checks
[upgrade/version] You have chosen to change the cluster version to "v1.18.0"
[upgrade/versions] Cluster version: v1.17.3
[upgrade/versions] kubeadm version: v1.18.0
[upgrade/confirm] Are you sure you want to proceed with the upgrade? [y/N]: y
[upgrade/prepull] Will prepull images for components [kube-apiserver kube-controller-manager kube-scheduler etcd]
[upgrade/prepull] Prepulling image for component etcd.
[upgrade/prepull] Prepulling image for component kube-apiserver.
[upgrade/prepull] Prepulling image for component kube-controller-manager.
[upgrade/prepull] Prepulling image for component kube-scheduler.
[apiclient] Found 0 Pods for label selector k8s-app=upgrade-prepull-etcd
[apiclient] Found 3 Pods for label selector k8s-app=upgrade-prepull-kube-controller-manager
[apiclient] Found 3 Pods for label selector k8s-app=upgrade-prepull-kube-apiserver
[apiclient] Found 0 Pods for label selector k8s-app=upgrade-prepull-kube-scheduler
[apiclient] Found 3 Pods for label selector k8s-app=upgrade-prepull-etcd
[apiclient] Found 3 Pods for label selector k8s-app=upgrade-prepull-kube-scheduler
[upgrade/prepull] Prepulled image for component etcd.
[upgrade/prepull] Prepulled image for component kube-scheduler.
[apiclient] Error getting Pods with label selector "k8s-app=upgrade-prepull-kube-apiserver" [etcdserver: request timed out]
[apiclient] Error getting Pods with label selector "k8s-app=upgrade-prepull-kube-controller-manager" [etcdserver: request timed out]
[upgrade/prepull] Prepulled image for component kube-controller-manager.
[upgrade/prepull] Prepulled image for component kube-apiserver.
[upgrade/prepull] Successfully prepulled the images for all the control plane components
[upgrade/apply] Upgrading your Static Pod-hosted control plane to version "v1.18.0"...
Static pod: kube-apiserver-ukm01 hash: 7e7a0d385fce06636ac0fc223274d299
Static pod: kube-controller-manager-ukm01 hash: fdad41767b3b13675192402b9a840a5c
Static pod: kube-scheduler-ukm01 hash: 703c43ab97818f969f780a2cbf4d24b7
[upgrade/etcd] Upgrading to TLS for etcd
[upgrade/etcd] Non fatal issue encountered during upgrade: the desired etcd version for this Kubernetes version "v1.18.0" is "3.4.3-0", but the current etcd version is "3.4.3". Won't downgrade etcd, instead just continue
[upgrade/staticpods] Writing new Static Pod manifests to "/etc/kubernetes/tmp/kubeadm-upgraded-manifests739015179"
W0403 09:40:19.888673   21690 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
[upgrade/staticpods] Preparing for "kube-apiserver" upgrade
[upgrade/staticpods] Renewing apiserver certificate
[upgrade/staticpods] Renewing apiserver-kubelet-client certificate
[upgrade/staticpods] Renewing front-proxy-client certificate
[upgrade/staticpods] Renewing apiserver-etcd-client certificate
[upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-apiserver.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2020-04-03-09-40-18/kube-apiserver.yaml"
[upgrade/staticpods] Waiting for the kubelet to restart the component
[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
Static pod: kube-apiserver-ukm01 hash: 7e7a0d385fce06636ac0fc223274d299
Static pod: kube-apiserver-ukm01 hash: 7e7a0d385fce06636ac0fc223274d299
Static pod: kube-apiserver-ukm01 hash: 7e7a0d385fce06636ac0fc223274d299
Static pod: kube-apiserver-ukm01 hash: 7e7a0d385fce06636ac0fc223274d299
Static pod: kube-apiserver-ukm01 hash: 7e7a0d385fce06636ac0fc223274d299
Static pod: kube-apiserver-ukm01 hash: 7e7a0d385fce06636ac0fc223274d299
Static pod: kube-apiserver-ukm01 hash: f9ef3245bc9735275ed5508f8bbea7e1
[apiclient] Found 3 Pods for label selector component=kube-apiserver
[upgrade/staticpods] Component "kube-apiserver" upgraded successfully!
[upgrade/staticpods] Preparing for "kube-controller-manager" upgrade
[upgrade/staticpods] Renewing controller-manager.conf certificate
[upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-controller-manager.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2020-04-03-09-40-18/kube-controller-manager.yaml"
[upgrade/staticpods] Waiting for the kubelet to restart the component
[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
Static pod: kube-controller-manager-ukm01 hash: fdad41767b3b13675192402b9a840a5c
Static pod: kube-controller-manager-ukm01 hash: 24e6dad5d81a4c5257a7b29861a48543
[apiclient] Found 3 Pods for label selector component=kube-controller-manager
[upgrade/staticpods] Component "kube-controller-manager" upgraded successfully!
[upgrade/staticpods] Preparing for "kube-scheduler" upgrade
[upgrade/staticpods] Renewing scheduler.conf certificate
[upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-scheduler.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2020-04-03-09-40-18/kube-scheduler.yaml"
[upgrade/staticpods] Waiting for the kubelet to restart the component
[upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
Static pod: kube-scheduler-ukm01 hash: 703c43ab97818f969f780a2cbf4d24b7
Static pod: kube-scheduler-ukm01 hash: b10b96b094242086df7de02b74f10de2
[apiclient] Found 3 Pods for label selector component=kube-scheduler
[upgrade/staticpods] Component "kube-scheduler" upgraded successfully!
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.18" in namespace kube-system with the configuration for the kubelets in the cluster
[kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.18" ConfigMap in the kube-system namespace
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.18.0". Enjoy!

[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.

取消隔离

 kubectl uncordon ukm01
node/ukm01 uncordoned

升级 kubectl 和 kubelet

apt-mark unhold kubelet kubectl && \
 apt-get update && apt-get install -y kubelet=1.18.0-00 kubectl=1.18.0-00 && \
 apt-mark hold kubelet kubectl

或者
apt-get update && \
 apt-get install -y --allow-change-held-packages kubelet=1.18.0-00 kubectl=1.18.0-00

升级其他master节点 kubeadm

ansible master:\!ans -m shell -a 'apt-mark unhold kubeadm && apt-get update && apt-get install -y kubeadm=1.18.0-00 && apt-mark hold kubeadm'
ansible master:\!ans -m shell -a 'apt-mark unhold kubelet kubectl && apt-get update && apt-get install -y kubelet=1.18.0-00 kubectl=1.18.0-00 && apt-mark hold kubelet kubectl'
ansible master:\!ans -m shell -a 'kubeadm version'

升级 master 节点 kubernetes

kubectl drain ukm02 --ignore-daemonsets
ssh ukm02
kubeadm upgrade node
exit
kubectl uncordon ukm02

升级 master 节点 kubectl 和 kubelet

ansible master -m shell -a 'apt-mark unhold kubelet kubectl && apt-get update && apt-get install -y kubelet=1.18.0-00 kubectl=1.18.0-00 && apt-mark hold kubelet kubectl'

重启 master 节点 kubelet

ansible master -m shell -a 'systemctl restart kubelet'

确认升级成功

 kubectl get nodes
NAME    STATUS   ROLES    AGE   VERSION
uki01   Ready    infra    8d    v1.17.3
uki02   Ready    infra    8d    v1.17.3
uki03   Ready    infra    8d    v1.17.3
ukm01   Ready    master   8d    v1.18.0
ukm02   Ready    master   8d    v1.18.0
ukm03   Ready    master   8d    v1.18.0
ukn01   Ready    worker   8d    v1.17.3
ukn02   Ready    worker   8d    v1.17.3
ukn03   Ready    worker   8d    v1.17.3

升级 infra 和 worker 节点 kubeadm

ansible infra:worker -m shell -a 'apt-mark unhold kubeadm && apt-get update && apt-get install -y kubeadm=1.18.0-00 && apt-mark hold kubeadm'

升级 infra 和 worker 节点 kubernetes

kubectl drain uki01 --ignore-daemonsets
ssh uki01
kubeadm upgrade node
exit
kubectl uncordon uki01

升级 infra 和 worker 节点 kubectl 和 kubelet

ansible infra:worker -m shell -a 'apt-mark unhold kubelet kubectl && apt-get update && apt-get install -y kubelet=1.18.0-00 kubectl=1.18.0-00 && apt-mark hold kubelet kubectl'

重启 infra 和 worker 节点 kubelet

ansible infra:worker -m shell -a 'systemctl restart kubelet'

检查 kubernetes 升级状态

 kubectl get nodes
NAME    STATUS   ROLES    AGE   VERSION
uki01   Ready    infra    8d    v1.18.0
uki02   Ready    infra    8d    v1.18.0
uki03   Ready    infra    8d    v1.18.0
ukm01   Ready    master   8d    v1.18.0
ukm02   Ready    master   8d    v1.18.0
ukm03   Ready    master   8d    v1.18.0
ukn01   Ready    worker   8d    v1.18.0
ukn02   Ready    worker   8d    v1.18.0
ukn03   Ready    worker   8d    v1.18.0

安装 router

router 是 openshift 开源的 ingress 服务,router 服务默认安装在 default namespace 下面。

配置 rbac 文件

 cat > router/rbac.yaml  <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: openshift-router
  namespace: default
rules:
- apiGroups: [""]
  resources: ["namespaces", "services", "endpoints"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["route.openshift.io"]
  resources: ["routes"]
  verbs: ["list", "watch"]
- apiGroups: ["route.openshift.io"]
  resources: ["routes/status"]
  verbs: ["get", "patch", "update"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: openshift-router
roleRef:
  apiGroup: ""
  kind: ClusterRole
  name: openshift-router
subjects:
- kind: ServiceAccount
  namespace: default
  name: router

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: openshift-router-auth-delegator
roleRef:
  apiGroup: ""
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  namespace: default
  name: router
EOF

配置 serviceaccount 文件

 cat > router/serviceaccount.yaml  <<EOF
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: router
  namespace: default
EOF

配置 crd 文件

 cat > router/crd.yaml  <<EOF
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
   name must match the spec fields below, and be in the form: <plural>.<group>
  name: routes.route.openshift.io
  namespace: default
spec:
   group name to use for REST API: /apis/<group>/<version>
  group: route.openshift.io
   list of versions supported by this CustomResourceDefinition
  versions:
    - name: v1
       Each version can be enabled/disabled by Served flag.
      served: true
       One and only one version must be marked as the storage version.
      storage: true
   either Namespaced or Cluster
  scope: Namespaced
  subresources:
     enable spec/status
    status: {}
  names:
     plural name to be used in the URL: /apis/<group>/<version>/<plural>
    plural: routes
     singular name to be used as an alias on the CLI and for display
    singular: route
     kind is normally the CamelCased singular type. Your resource manifests use this.
    kind: Route
  additionalPrinterColumns:
  - name: Host
    type: string
    JSONPath: .status.ingress[0].host
  - name: Admitted
    type: string
    JSONPath: .status.ingress[0].conditions[?(@.type=="Admitted")].status
  - name: Service
    type: string
    JSONPath: .spec.to.name
  - name: TLS
    type: string
    JSONPath: .spec.tls.type
EOF

配置 router 安装文件

 cat > router/deployment.yaml  <<EOF
---
apiVersion: apps/v1
kind: DaemonSet  Deployment DaemonSet
metadata:
  name: router
  namespace: default
  labels:
    k8s-app: router
spec:
  replicas: 3  如果是 DaemonSet,可以不设置副本数量。
  selector:
    matchLabels:
      k8s-app: router
  template:
    metadata:
      labels:
        k8s-app: router
    spec:
      serviceAccountName: router
      nodeSelector:
        node-role.kubernetes.io/infra: "true"
      containers:
      - env:
        - name: ROUTER_LISTEN_ADDR
          value: 0.0.0.0:1936
        - name: ROUTER_METRICS_TYPE
          value: haproxy
        - name: ROUTER_SERVICE_HTTPS_PORT
          value: "443"
        - name: ROUTER_SERVICE_HTTP_PORT
          value: "80"
        - name: ROUTER_THREADS
          value: "4"
        image: openshift/origin-haproxy-router:v4.0.0
        imagePullPolicy: IfNotPresent
        livenessProbe:
          httpGet:
            host: localhost
            path: /healthz
            port: 1936
          initialDelaySeconds: 10
        name: router
        ports:
        - containerPort: 80
        - containerPort: 443
        - containerPort: 1936
          name: stats
          protocol: TCP
        readinessProbe:
          httpGet:
            host: localhost
            path: healthz/ready
            port: 1936
          initialDelaySeconds: 10
        resources:
          requests:
            cpu: 100m
            memory: 256Mi
      hostNetwork: true
EOF

安装 router 服务

kubectl apply -f router/serviceaccount.yaml

kubectl apply -f router/rbac.yaml

kubectl apply -f router/deployment.yaml

kubectl apply -f router/crd.yaml

检查端口监听

load blance 配置 TCP 80/443/1936 端口转发到 infra 节点服务器。

ansible infra -m shell -a 'netstat -lntp|grep -E "80|443|1936"'

校验 route 服务

安装nginx

kubectl create deployment nginx --image nginx:alpine
kubectl expose deployment nginx --port=80

创建 nginx route

 kubectl apply -f - <<EOF
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  host: test.mokr.cn
  to:
    kind: Service
    name: nginx
    weight: 100
  wildcardPolicy: None
EOF

访问验证

 curl -ik http://test.mokr.cn --resolve 'test.mokr.cn:80:10.10.34.89'
HTTP/1.1 200 OK
Server: nginx/1.17.9
Date: Tue, 24 Mar 2020 07:01:43 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 03 Mar 2020 17:36:53 GMT
ETag: "5e5e95b5-264"
Accept-Ranges: bytes
Set-Cookie: 3bc5f7a8aec67b74b33e81d956f57cb9=5ffd533ac952a924e0ec8b6f1c601703; path=/; HttpOnly
Cache-control: private

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

 或者
 curl -ik http://10.10.34.89 -H 'Host: test.mokr.cn' -v

删除 router

kubectl delete -f router.yaml

安装 kubernetes dashboard 2.0

curl -L https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml -o kubernetes-dashboard.yaml

签发 https 访问证书

  • Can’t load /root/.rnd into RNG
cd /root
openssl rand -writerand .rnd

dashboard 多域名配置

 mkdir -p /certs

 cp /etc/ssl/openssl.cnf /certs
 vim /certs/openssl.cnf
...
[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = CN
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = GuangDong
localityName                    = Locality Name (eg, city)
localityName_default            = ShenZhen
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = MOKR Ltd
organizationalUnitName          = Organizational Unit Name (eg, section)
organizationalUnitName_default  = OPS
commonName                      = Common Name (e.g. server FQDN or YOUR name)
commonName_max                  = 64
emailAddress                    = Email Address
emailAddress_max                = 64
emailAddress_default            = seanzhau@gmail.com

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = dashboard.mokr.cn
DNS.2 = kubernetes-dashboard.kubernetes-dashboard.svc
DNS.3 = kubernetes-dashboard.kubernetes-dashboard.svc.cluster.local
IP.1 = 10.104.71.164
IP.2 = 10.10.34.89
...

签发 dashboard 密钥

openssl req -nodes -newkey rsa:2048 \
 -keyout /certs/dashboard.key \
 -out /certs/dashboard.csr \
 -subj "/C=CN/ST=GuangDong/L=ShenZhen/O=Mokr LTD/OU=OPS" \
 -config /certs/openssl.cnf \
 -extensions v3_req

签发 dashboard 证书

私钥签发
openssl x509 -req -sha256 -days 365 \
 -in /certs/dashboard.csr \
 -signkey /certs/dashboard.key \
 -out /certs/dashboard.crt \
 -extfile /certs/openssl.cnf \
 -extensions v3_req

ca 签发
openssl x509 -req -days 365 \
 -in /certs/dashboard.csr \
 -CA /etc/kubernetes/pki/ca.crt \
 -CAkey /etc/kubernetes/pki/ca.key \
 -CAcreateserial \
 -out /certs/dashboard.crt \
 -extfile /certs/openssl.cnf \
 -extensions v3_req

验证 dashboard 证书

 openssl x509 -text -noout -in /certs/dashboard.crt
Certificate:
...
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Key Usage:
                Digital Signature, Non Repudiation, Key Encipherment
            X509v3 Subject Alternative Name:
                DNS:dashboard.mokr.cn, DNS:kubernetes-dashboard.kubernetes-dashboard.svc, DNS:kubernetes-dashboard.kubernetes-dashboard.svc.cluster.local, IP Address:10.104.71.164, IP Address:10.10.34.89
...

部署 dashboard

kubectl apply -f kubernetes-dashboard.yaml

为 dashboard 配置 secret 证书

kubectl create secret generic kubernetes-dashboard-certs --from-file=/certs/dashboard -n kubernetes-dashboard

可不配置
kubectl create secret tls kubernetes-dashboard-tls --cert=/certs/dashboard/dashboard.crt --key=/certs/dashboard/dashboard.key -n kubernetes-dashboard

校验 dashboard

 kubectl get pods,svc -n kubernetes-dashboard
NAME                                             READY   STATUS    RESTARTS   AGE
pod/dashboard-metrics-scraper-566cddb686-m5dzb   1/1     Running   0          22h
pod/kubernetes-dashboard-7b5bf5d559-dbrh2        1/1     Running   0          22h

NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/dashboard-metrics-scraper   ClusterIP   10.107.240.229   <none>        8000/TCP   22h
service/kubernetes-dashboard        ClusterIP   10.96.188.203    <none>        443/TCP    22h

创建 dashboard route

 kubectl apply -f -  <<EOF
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: kubernetes-dashboard
  labels:
    app: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  host: dashboard.mokr.cn
  tls:
    insecureEdgeTerminationPolicy: Redirect ## None Allow Redirect
    termination: reencrypt ## edge passthrough reencrypt
  to:
    kind: Service
    name: kubernetes-dashboard
    weight: 100
  wildcardPolicy: None
EOF

curl 访问 dashboard

curl -ik https://dashboard.mokr.cn --resolve 'dashboard.mokr.cn:443:10.10.34.89'

或者

curl -ik https://10.10.34.89 -H 'Host: dashboard.mokr.cn'

创建 dashboard 用户

 创建用户
 kubectl create serviceaccount seanzhau -n kubernetes-dashboard

 添加用户授权,配置集群 admin 权限
## ex: kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1
 kubectl create clusterrolebinding dashboard-admin --clusterrole cluster-admin --serviceaccount kubernetes-dashboard:seanzhau

 或者
 kubectl apply -f - <<EOF
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: seanzhau
  namespace: kubernetes-dashboard
  labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dashboard-admin
  namespace: kubernetes-dashboard
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: seanzhau
  namespace: kubernetes-dashboard
EOF

查看 secret 信息

查看 secret 私钥或者 ca 信息
kubectl -n kubernetes-dashboard get secret -o jsonpath='{range .items[?(@.metadata.annotations.kubernetes\.io/service-account\.name=="seanzhau")].data}{.ca\.crt}{end}' | base64 -d

查看用户 token
kubectl -n kubernetes-dashboard get secret -o jsonpath='{range .items[?(@.metadata.annotations.kubernetes\.io/service-account\.name=="seanzhau")].data}{.token}{end}' | base64 -d

浏览器访问

浏览器打开 https://dashboard.mokr.cn ,选择 Token ,输入获取的用户 token。

使用 kubeconfig 登录

下载 /etc/kubernetes/admin.conf 到本地,修改配置文件,在最底部添加 token 字段。

 vim admin.conf
...
users:
- name: kubernetes-admin
  user:
    client-certificate-data: xxxxxxxxxxxxxxxxxxxxx
    client-key-data: xxxxxxxxxxxxxxxxxxxxx
    token: xxxxxxxxxxxxxxxxxxxxx

安装 ceph 存储

ceph ansible 安装

git clone -b stable-5.0 https://github.com/ceph/ceph-ansible.git
cd ceph-ansible

安装 pip

apt install -y python-pip

配置 pip 源

 mkdir -p ~/.pip
 cat > ~/.pip/pip.conf <<EOF
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/

[install]
trusted-host=mirrors.aliyun.com
EOF

安装 ansible 以及依赖

pip install -r requirements.txt

配置 ansible 资产文件

 cat  > dummy-ansible-hosts <<EOF
[mons]
10.10.34.29
10.10.34.31
10.10.34.42

[osds]
10.10.34.29
10.10.34.31
10.10.34.42

[mdss]
10.10.34.29
10.10.34.31
10.10.34.42

[rgws]
10.10.34.29
10.10.34.31
10.10.34.42

[mgrs]
10.10.34.29
10.10.34.31
10.10.34.42

[grafana-server]
10.10.34.29

[clients]
10.10.34.29
10.10.34.31
10.10.34.42
EOF

配置 ceph 安装文件

 docker 安装
 cp site-container.yml.sample site-container.yml

 二进制文件安装
 cp site.yml.sample site.yml

 cat > group_vars/all.yml <<EOF
---
cluster: ceph
generate_fsid: true
journal_size: 512
ceph_origin: repository
ceph_repository: community

 docker 安装
ceph_docker_image: "ceph/daemon"
ceph_docker_image_tag: latest-octopus
containerized_deployment: true
ceph_docker_registry: docker.io
ceph_stable_repo: "{{ ceph_mirror }}/debian-{{ ceph_stable_release }}"

 二进制安装
ceph_mirror: http://mirrors.aliyun.com/ceph
ceph_stable_key: http://mirrors.aliyun.com/ceph/keys/release.asc
ceph_stable_release: octopus

public_network: "10.10.34.0/24"
cluster_network: "10.10.34.0/24"
monitor_interface: eth0
osd_objectstore: bluestore
dmcrypt: false
devices:
  - /dev/vdb
  - /dev/vdc
radosgw_interface: eth0
radosgw_address: 0.0.0.0
radosgw_address_block: "10.10.34.0/24"
grafana_admin_user: seanzhau
grafana_admin_password: iPaaS2020
dashboard_enabled: True
dashboard_admin_user: seanzhau
dashboard_admin_password: iPaaS2020
EOF

安装 ceph 集群

docker 安装
ansible-playbook -i dummy-ansible-hosts site-container.yml

二进制文件安装
ansible-playbook -i dummy-ansible-hosts site.yml

非集群节点安装 ceph 客户端

apt install -y ceph-common

配置客户端

 配置 ceph.conf
 cat > /etc/ceph/ceph.conf <<EOF
[global]
mon host = 10.10.34.29,10.10.34.31,10.10.34.42
EOF

 从 ceph 集群复制 admin key
 scp 10.10.34.29:/etc/ceph/ceph.client.admin.keyring /etc/ceph/ceph.client.admin.keyring

查看集群状态

ceph -s
 cluster:
   id:     5ae77bc9-1831-42df-8ef2-956499ce685b
   health: HEALTH_WARN
           1 pools have too few placement groups

 services:
   mon: 3 daemons, quorum ceph01,ceph02,ceph03 (age 15m)
   mgr: ceph01(active, since 14m), standbys: ceph02, ceph03
   mds: cephfs:1 {0=ceph01=up:active} 2 up:standby
   osd: 6 osds: 6 up (since 19m), 6 in (since 19m)
   rgw: 3 daemons active (ceph01.rgw0, ceph02.rgw0, ceph03.rgw0)

 task status:
   scrub status:
       mds.ceph01: idle

 data:
   pools:   7 pools, 121 pgs
   objects: 215 objects, 11 KiB
   usage:   6.1 GiB used, 2.9 TiB / 2.9 TiB avail
   pgs:     121 active+clean

查看磁盘状态

 ceph osd tree
ID  CLASS  WEIGHT   TYPE NAME                STATUS  REWEIGHT  PRI-AFF
-1         2.92978  root default
-3         0.97659      host ceph01
 0    hdd  0.48830          osd.0                up   1.00000  1.00000
 3    hdd  0.48830          osd.3                up   1.00000  1.00000
-7         0.97659      host ceph02
 2    hdd  0.48830          osd.2                up   1.00000  1.00000
 5    hdd  0.48830          osd.5                up   1.00000  1.00000
-5         0.97659      host ceph03
 1    hdd  0.48830          osd.1                up   1.00000  1.00000
 4    hdd  0.48830          osd.4                up   1.00000  1.00000

挂载 ceph

 mount.ceph 10.10.34.29,10.10.34.31,10.10.34.42:/ /mnt/ -o name=admin,secret=admin-password   secretfile=/root/admin.secret

 df -h /mnt/
Filesystem                             Size  Used Avail Use% Mounted on
10.10.34.29,10.10.34.31,10.10.34.42:/  948G     0  948G   0% /mnt

删除集群

docker 卸载
ansible-playbook -i dummy-ansible-hosts infrastructure-playbooks/purge-container-cluster.yml

二进制文件卸载
ansible-playbook -i dummy-ansible-hosts infrastructure-playbooks/purge-cluster.yml

删除磁盘分区信息

RuntimeError: Unable to use device, already a member of LVM: /dev/vdb

ansible -i dummy-ansible-hosts osds -m shell -a 'wipefs -a /dev/vdb --force'

配置 provisioner

下载 ceph images

docker pull quay.io/external_storage/rbd-provisioner:latest
docker pull quay.io/external_storage/cephfs-provisioner:latest

创建 ceph namespace

kubectl create namespace ceph

安装 cephfs

生成 cephfs admin 密码

ceph auth get-key client.admin > /tmp/key

创建 cephfs secret

kubectl create secret generic cephfs-secret-admin --from-file=/tmp/key --namespace=ceph --type=kubernetes.io/cephfs

创建 cephfs 安装文件

mkdir -p storageClass/cephfs

重新构建 image

如果有权限问题,可以按操作重新制造 image。

 cat > storageClass/cephfs/Dockerfile <<EOF
FROM quay.io/external_storage/cephfs-provisioner:latest

USER root

RUN sed -i 's|0o755|0o777|g' /usr/lib/python2.7/site-packages/ceph_volume_client.py
EOF

 docker build -t quay.io/external_storage/cephfs-provisioner:new storageClass/cephfs/

创建 cephfs deployment 安装文件

 cat > storageClass/cephfs/deployment.yaml <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cephfs-provisioner
  namespace: ceph
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cephfs-provisioner
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: cephfs-provisioner
    spec:
      nodeSelector:
        node-role.kubernetes.io/infra: "true"
      containers:
      - name: cephfs-provisioner
        image: "quay.io/external_storage/cephfs-provisioner:latest"
        imagePullPolicy: IfNotPresent
        env:
        - name: PROVISIONER_NAME
          value: ceph.com/cephfs
        - name: PROVISIONER_SECRET_NAMESPACE
          value: ceph
        command:
        - "/usr/local/bin/cephfs-provisioner"
        args:
        - "-id=cephfs-provisioner-1"
      serviceAccount: cephfs-provisioner
EOF

创建 cephfs serviceaccount 安装文件

 cat > storageClass/cephfs/serviceaccount.yaml <<EOF
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cephfs-provisioner
  namespace: ceph
EOF

创建 cephfs rbac 安装文件

 cat > storageClass/cephfs/rbac.yaml <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cephfs-provisioner
  namespace: ceph
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["create", "get", "delete"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cephfs-provisioner
  namespace: ceph
subjects:
- kind: ServiceAccount
  name: cephfs-provisioner
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cephfs-provisioner

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cephfs-provisioner
  namespace: ceph
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
  - apiGroups: [""]
    resources: ["services"]
    resourceNames: ["kube-dns","coredns"]
    verbs: ["list", "get"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cephfs-provisioner
subjects:
  - kind: ServiceAccount
    name: cephfs-provisioner
    namespace: ceph
roleRef:
  kind: ClusterRole
  name: cephfs-provisioner
  apiGroup: rbac.authorization.k8s.io
EOF

创建 cephfs storageclass 安装文件

 cat > storageClass/cephfs/storageclass.yaml <<EOF
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: cephfs-provisioner
provisioner: ceph.com/cephfs
parameters:
    monitors: "10.10.34.29:6789,10.10.34.31:6789,10.10.34.42:6789"
    adminId: admin
    adminSecretName: cephfs-secret-admin
    adminSecretNamespace: ceph
    claimRoot: /storage
EOF

安装 cephfs provisioner

kubectl apply -f storageClass/cephfs/serviceaccount.yaml

kubectl apply -f storageClass/cephfs/rbac.yaml

kubectl apply -f storageClass/cephfs/deployment.yaml

kubectl apply -f storageClass/cephfs/storageclass.yaml

查看 cephfs provisioner

 kubectl get storageclasses cephfs-provisioner
NAME                 PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
cephfs-provisioner   ceph.com/cephfs   Delete          Immediate           false                  17s

创建 cephfs PVC

 cat > storageClass/cephfs/pvc.yaml <<EOF
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cephfs-test
spec:
  storageClassName: cephfs-provisioner
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
EOF

 kubectl apply -f storageClass/cephfs/pvc.yaml -n kube-system
 kubectl apply -f storageClass/cephfs/pvc.yaml -n ceph
 kubectl apply -f storageClass/cephfs/pvc.yaml -n default

验证 cephfs PVC

 kubectl get pvc --all-namespaces
NAMESPACE     NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS         AGE
ceph          cephfs-test   Bound    pvc-ae5ff9f8-4032-4690-9104-eeb563d45a1e   5Gi        RWX            cephfs-provisioner   8s
default       cephfs-test   Bound    pvc-85d47294-50a0-4f6c-b9ca-7a676cf3c34e   5Gi        RWX            cephfs-provisioner   5s
kube-system   cephfs-test   Bound    pvc-759c1b48-df22-4b72-ab22-490a2f3ebd5c   5Gi        RWX            cephfs-provisioner   13s

创建 rbd

生成 rbd admin 密码

ceph auth get-key client.admin > /tmp/key

创建 admin secret

kubectl create secret generic rbd-secret-admin  --from-file=/tmp/key --namespace=ceph --type=kubernetes.io/rbd

创建 pool secret

ceph osd pool create kube 8 8

ceph auth add client.kube mon 'allow r' osd 'allow rwx pool=kube'

ceph auth get-key client.kube > /tmp/key

kubectl create secret generic kube-secret --from-file=/tmp/key --namespace=ceph --type=kubernetes.io/rbd

创建 rbd 目录

mkdir -p storageClass/rbd

创建 rbd deployment 安装文件

 cat > storageClass/rbd/deployment.yaml <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rbd-provisioner
  namespace: ceph
spec:
  replicas: 1
  selector:
    matchLabels:
      app: rbd-provisioner
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: rbd-provisioner
    spec:
      nodeSelector:
        node-role.kubernetes.io/infra: "true"
      containers:
      - name: rbd-provisioner
        image: "quay.io/external_storage/rbd-provisioner:latest"
        imagePullPolicy: IfNotPresent
        env:
        - name: PROVISIONER_NAME
          value: ceph.com/rbd
      serviceAccount: rbd-provisioner
EOF

创建 rbd serviceaccount 安装文件

 cat > storageClass/rbd/serviceaccount.yaml <<EOF
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: rbd-provisioner
  namespace: ceph
EOF

创建 rbd rbac 安装文件

 cat > storageClass/rbd/rbac.yaml <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rbd-provisioner
  namespace: ceph
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]
- apiGroups: [""]
  resources: ["endpoints"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rbd-provisioner
  namespace: ceph
subjects:
- kind: ServiceAccount
  name: rbd-provisioner
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: rbd-provisioner

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rbd-provisioner
  namespace: ceph
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
  - apiGroups: [""]
    resources: ["services"]
    resourceNames: ["kube-dns","coredns"]
    verbs: ["list", "get"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: rbd-provisioner
subjects:
  - kind: ServiceAccount
    name: rbd-provisioner
    namespace: ceph
roleRef:
  kind: ClusterRole
  name: rbd-provisioner
  apiGroup: rbac.authorization.k8s.io
EOF

创建 rbd storageclass 安装文件

 cat > storageClass/rbd/storageclass.yaml <<EOF
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: rbd-provisioner
provisioner: ceph.com/rbd
parameters:
  monitors: "10.10.34.29:6789,10.10.34.31:6789,10.10.34.42:6789"
  pool: kube
  adminId: admin
  adminSecretNamespace: ceph
  adminSecretName: rbd-secret-admin
  userId: kube
  userSecretNamespace: ceph
  userSecretName: ceph-secret
  imageFormat: "2"
  imageFeatures: layering
EOF

安装 rbd provisioner

kubectl apply -f storageClass/rbd/serviceaccount.yaml

kubectl apply -f storageClass/rbd/rbac.yaml

kubectl apply -f storageClass/rbd/deployment.yaml

kubectl apply -f storageClass/rbd/storageclass.yaml

查看 rbd provisioner

 kubectl get storageclasses rbd-provisioner
NAME              PROVISIONER    RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
rbd-provisioner   ceph.com/rbd   Delete          Immediate           false                  7s

创建 rbd PVC

 cat > storageClass/rbd/pvc.yaml <<EOF
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-test
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: rbd-provisioner
  resources:
    requests:
      storage: 10Gi
EOF

 kubectl apply -f storageClass/rbd/pvc.yaml -n kube-system
 kubectl apply -f storageClass/rbd/pvc.yaml -n ceph
 kubectl apply -f storageClass/rbd/pvc.yaml -n default

验证 rbd PVC

 kubectl get pvc --all-namespaces
NAMESPACE     NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS         AGE
ceph          rbd-test      Bound    pvc-4d85ad48-b24c-43b6-a7c2-89aec9c661a7   10Gi       RWO            rbd-provisioner      19s
default       rbd-test      Bound    pvc-9d93ccbd-b6ed-42fe-8f57-78fbff88baeb   10Gi       RWO            rbd-provisioner      11s
kube-system   rbd-test      Bound    pvc-5887166f-d9b4-4d40-b419-2e37ac81901d   10Gi       RWO            rbd-provisioner      31s

对象存储

s3 存储

 配置 ceph s3 账号,保留 access_key 和 secret_key
 radosgw-admin user create --uid="testuser" --display-name="test user"
{
    "user_id": "testuser",
    "display_name": "test user",
    "email": "",
    "suspended": 0,
    "max_buckets": 1000,
    "subusers": [],
    "keys": [
        {
            "user": "testuser",
            "access_key": "60DD3SXN58LIRC06ILQE",
            "secret_key": "zgFnP3lL3uPF3WsCeQtnESKvgPYHnW75cSJfkYeZ"
        }
    ],
    "swift_keys": [],
    "caps": [],
    "op_mask": "read, write, delete",
    "default_placement": "",
    "default_storage_class": "",
    "placement_tags": [],
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "user_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "temp_url_keys": [],
    "type": "rgw",
    "mfa_ids": []
}

 安装 s3 python 库
 pip install boto

 创建 s3 测试文件,使用上面创建的账号。
 cat > s3.py <<EOF
from boto.s3.connection import S3Connection
from boto.s3.connection import OrdinaryCallingFormat


 add radosgw user in ceph cluster
 radosgw-admin user create --uid=rgwuser --subuser=rgwuser:swift --display-name=s3 --access=full

conn = S3Connection(aws_access_key_id='60DD3SXN58LIRC06ILQE',
                    aws_secret_access_key='zgFnP3lL3uPF3WsCeQtnESKvgPYHnW75cSJfkYeZ',
                    host='10.10.34.29',
                    port=8080,
                    is_secure=False,
                    calling_format=OrdinaryCallingFormat())

create_bucket = conn.create_bucket('cephfs')

buckets_list = conn.get_all_buckets()
for bucket in buckets_list:
     print('%s\t%s' % (bucket.name, bucket.creation_date))

delete_bucket = conn.delete_bucket('cephfs')
EOF

 测试验证
 python s3.py
cephfs  2020-04-10T08:16:15.647Z

swift

 创建账号
 radosgw-admin subuser create --uid=testuser --subuser=testuser:swift --access=full
{
    "user_id": "testuser",
    "display_name": "test user",
    "email": "",
    "suspended": 0,
    "max_buckets": 1000,
    "subusers": [
        {
            "id": "testuser:swift",
            "permissions": "full-control"
        }
    ],
    "keys": [
        {
            "user": "testuser",
            "access_key": "60DD3SXN58LIRC06ILQE",
            "secret_key": "zgFnP3lL3uPF3WsCeQtnESKvgPYHnW75cSJfkYeZ"
        }
    ],
    "swift_keys": [
        {
            "user": "testuser:swift",
            "secret_key": "b59Aw59eiStnhibukAm7fN3vQRtTU2BwNio2dHnl"
        }
    ],
    "caps": [],
    "op_mask": "read, write, delete",
    "default_placement": "",
    "default_storage_class": "",
    "placement_tags": [],
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "user_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "temp_url_keys": [],
    "type": "rgw",
    "mfa_ids": []
}

 重置密码
 radosgw-admin key create --subuser=testuser:swift --key-type=swift --gen-secret

 安装 swift 客户端
 pip install python-swiftclient

 测试
 swift -A http://10.10.34.29:8080/auth/1.0 -U testuser:swift -K 'b59Aw59eiStnhibukAm7fN3vQRtTU2BwNio2dHnl' list

安装 istio

使用 demo 安装

  • 参考 https://istio.io/docs/setup/additional-setup/config-profiles/
istioctl manifest apply --set profile=demo --set values.gateways.istio-ingressgateway.type=NodePort

自定义参数安装

  • 参数 https://istio.io/zh/docs/reference/config/installation-options/
istioctl manifest apply \
 --namespace istio-system \
 --set values.global.hub=docker.io/istio \
 --set values.global.tag=1.5.0 \
 --set values.global.logging.level="default:info" \
 --set values.global.imagePullPolicy=IfNotPresent \
 --set values.global.k8sIngress.enabled=false \
 --set values.global.k8sIngress.enableHttps=false \
 --set values.global.proxy.image=proxyv2 \
 --set values.global.proxy.clusterDomain="cluster.local" \
 --set values.global.proxy.privileged=true \
 --set values.global.proxy.enableCoreDump=true \
 --set values.global.proxy.autoInject=enabled \
 --set values.global.proxy.tracer=zipkin \
 --set values.global.controlPlaneSecurityEnabled=true \
 --set values.global.mtls.enabled=false \
 --set values.global.outboundTrafficPolicy.mode=ALLOW_ANY \
 --set values.global.sds.enabled=false \
 --set values.certmanager.enabled=false \
 --set values.galley.enabled=true \
 --set values.gateways.enabled=true \
 --set values.gateways.istio-ingressgateway.enabled=true \
 --set values.gateways.istio-ingressgateway.type=NodePort  NodePort, ClusterIP or LoadBalancer \
 --set values.gateways.istio-egressgateway.enabled=true \
 --set values.grafana.enabled=true \
 --set values.istio_cni.enabled=false \
 --set values.istiocoredns.enabled=false \
 --set values.kiali.enabled=true \
 --set values.kiali.createDemoSecret=true \
 --set values.kiali.hub=docker.io/kiali \
 --set values.mixer.policy.enabled=false \
 --set values.mixer.policy.autoscaleEnabled=true \
 --set values.nodeagent.enabled=false \
 --set values.pilot.enabled=true \
 --set values.pilot.sidecar=true \
 --set values.prometheus.enabled=true \
 --set values.security.enabled=true \
 --set values.sidecarInjectorWebhook.enabled=true \
 --set values.sidecarInjectorWebhook.enableNamespacesByDefault=true \
 --set values.tracing.enabled=true \
 --set values.tracing.jaeger.hub=docker.io/jaegertracing \
 --set values.tracing.jaeger.tag=1.14

查看 ingress 端口监听情况

 kubectl get svc -n istio-system | grep ingress
istio-ingressgateway        NodePort    10.105.16.129    <none>        15020:30796/TCP,80:32179/TCP,443:31133/TCP,15029:31338/TCP,15030:30980/TCP,15031:31675/TCP,15032:32296/TCP,31400:31821/TCP,15443:32679/TCP   30s

 ansible ins -m shell -a 'netstat -lntp | grep -E "32179|31133"'
10.10.34.92 | CHANGED | rc=0 >>
tcp6       0      0 :::32179                :::*                    LISTEN      21780/kube-proxy
tcp6       0      0 :::31133                :::*                    LISTEN      21780/kube-proxy
10.10.34.94 | CHANGED | rc=0 >>
tcp6       0      0 :::32179                :::*                    LISTEN      3093/kube-proxy
tcp6       0      0 :::31133                :::*                    LISTEN      3093/kube-proxy
10.10.34.100 | CHANGED | rc=0 >>
tcp6       0      0 :::32179                :::*                    LISTEN      14998/kube-proxy
tcp6       0      0 :::31133                :::*                    LISTEN      14998/kube-proxy
10.10.34.99 | CHANGED | rc=0 >>
tcp6       0      0 :::31133                :::*                    LISTEN      3031/kube-proxy
tcp6       0      0 :::32179                :::*                    LISTEN      3031/kube-proxy
10.10.34.95 | CHANGED | rc=0 >>
tcp6       0      0 :::32179                :::*                    LISTEN      23912/kube-proxy
tcp6       0      0 :::31133                :::*                    LISTEN      23912/kube-proxy
10.10.34.96 | CHANGED | rc=0 >>
tcp6       0      0 :::32179                :::*                    LISTEN      26951/kube-proxy
tcp6       0      0 :::31133                :::*                    LISTEN      26951/kube-proxy
10.10.34.93 | CHANGED | rc=0 >>
tcp6       0      0 :::31133                :::*                    LISTEN      31622/kube-proxy
tcp6       0      0 :::32179                :::*                    LISTEN      31622/kube-proxy
10.10.34.97 | CHANGED | rc=0 >>
tcp6       0      0 :::32179                :::*                    LISTEN      4244/kube-proxy
tcp6       0      0 :::31133                :::*                    LISTEN      4244/kube-proxy
10.10.34.98 | CHANGED | rc=0 >>
tcp6       0      0 :::31133                :::*                    LISTEN      8077/kube-proxy
tcp6       0      0 :::32179                :::*                    LISTEN      8077/kube-proxy

配置 load blance

  • LB 80 端口的 TCP 协议请求转发到集群 node 节点的 32179 端口
  • LB 443 端口的 TCP 协议请求转发到集群 node 节点的 31133 端口

应用测试

创建 namespace 并打开自动注入

kubectl create namespace book

kubectl label namespace book istio-injection=enabled

创建 demo

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n book

kubectl get services -n book

kubectl get pods -n book

kubectl exec -n book \
 -it $(kubectl get pod  -n book -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings \
 -- curl productpage:9080/productpage | grep -o "<title>.*</title>"

创建 http gateway

 kubectl apply -f - <<EOF
--
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: book
  namespace: book
spec:
  hosts:
  - "book.mokr.cn"
  gateways:
  - istio-system/ingressgateway
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080
EOF

验证 http gateway

curl -ik http://book.mokr.cn --resolve 'book.mokr.cn:443:10.10.34.89' -v

创建 https gateway

 创建根证书
 openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout mokr.cn.key -out mokr.cn.crt -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=mokr/OU=ops/CN=mokr.cn"

 创建域名 key
 openssl req -out book.mokr.cn.csr -newkey rsa:2048 -nodes -keyout book.mokr.cn.key -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=mokr/OU=ops/CN=book.mokr.cn"

 创建域名证书
 openssl x509 -req -days 365 -CA mokr.cn.crt -CAkey mokr.cn.key -set_serial 0 -in book.mokr.cn.csr -out book.mokr.cn.crt

 创建 tls secret
 kubectl create secret tls ingressgateway-book-certs --key book.mokr.cn.key --cert book.mokr.cn.crt  -n istio-system

 创建 https gateway
 kubectl apply -f - <<EOF
--
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: book-gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - book.mokr.cn
    tls:
      httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: HTTPS   HTTP | HTTPS | GRPC | HTTP2 | MONGO | TCP | TLS
    tls:
      mode: SIMPLE    PASSTHROUGH | SIMPLE | MUTUAL | AUTO_PASSTHROUGH | ISTIO_MUTUAL
      credentialName: ingressgateway-book-certs
    hosts:
    - book.mokr.cn
EOF

 创建 https VirtualService
 kubectl apply -f - <<EOF
--
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: book
  namespace: book
spec:
  hosts:
  - "book.mokr.cn"
  gateways:
  - istio-system/book-gateway
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080
EOF

查看安装情况

 kubectl get gateway -n book
NAME               AGE
bookinfo-gateway   23s

 kubectl get virtualservice -n book
NAME       GATEWAYS             HOSTS                       AGE
bookinfo   [bookinfo-gateway]   [book.mokr.cn]   36s

验证 https gateway

curl -ik https://book.mokr.cn --resolve 'book.mokr.cn:443:10.10.34.89' -v

删除 demo

kubectl delete -f samples/bookinfo/platform/kube/bookinfo.yaml -n book

kubectl delete namespace book --force --grace-period=0

删除 istioctl 集群

istioctl manifest generate | kubectl delete -f -

部署 registry

创建 pvc 部署文件

 cat > registry/pvc.yaml <<EOF
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: registry-storage
spec:
  storageClassName: cephfs-provisioner
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
EOF

创建 service 部署文件

 cat > registry/service.yaml <<EOF
---
apiVersion: v1
kind: Service
metadata:
  name: docker-registry
  namespace: default
spec:
  ports:
  - port: 5000
    protocol: TCP
    targetPort: 5000
  selector:
    k8s-app: docker-registry
  sessionAffinity: None
  type: ClusterIP
EOF

创建 registry 部署文件

 cat > registry/deployment.yaml <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: docker-registry
  name: docker-registry
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: docker-registry
  template:
    metadata:
      labels:
        k8s-app: docker-registry
    spec:
      nodeSelector:
        node-role.kubernetes.io/infra: "true"
      containers:
      - env:
        - name: REGISTRY_HTTP_ADDR
          value: :5000
        - name: REGISTRY_HTTP_TLS_CERTIFICATE
          value: /etc/secrets/tls.crt
        - name: REGISTRY_HTTP_TLS_KEY
          value: /etc/secrets/tls.key
        - name: REGISTRY_STORAGE_DELETE_ENABLED
          value: "true"
        name: registry
        image: registry:2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 5000
          protocol: TCP
        resources:
          requests:
            cpu: 100m
            memory: 256Mi
        volumeMounts:
        - name: registry-data
          mountPath: /var/lib/registry
        - name: registry-certificates
          mountPath: /etc/secrets
      serviceAccountName: docker-registry
      volumes:
      - name: registry-data
        persistentVolumeClaim:
          claimName: registry-storage
      - name: registry-certificates
        secret:
          defaultMode: 420
          secretName: registry-certificates
EOF

创建 service

kubectl apply -f registry/service.yaml

kubectl get svc docker-registry -o custom-columns=clusterIP:.spec.clusterIP

配置多域名

 mkdir -p registry/

 cp /etc/ssl/openssl.cnf registry/
 vim registry/openssl.cnf
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = docker-registry.mokr.cn
DNS.2 = docker-registry.default.svc
DNS.3 = docker-registry.default.svc.cluster.local

签发 registry 密钥

openssl req -nodes -newkey rsa:2048 \
 -keyout registry/docker-registry.key \
 -out registry/docker-registry.csr \
 -subj "/C=CN/ST=GuangDong/L=ShenZhen/O=Mokr LTD/OU=OPS" \
 -config registry/openssl.cnf \
 -extensions v3_req

签发 registry 证书

私钥签发
openssl x509 -req -sha256 -days 365 \
 -in registry/docker-registry.csr \
 -signkey registry/docker-registry.key \
 -out registry/docker-registry.crt \
 -extfile registry/openssl.cnf \
 -extensions v3_req

ca 签发
openssl x509 -req -days 365 \
 -in registry/docker-registry.csr \
 -CA /etc/kubernetes/pki/ca.crt \
 -CAkey /etc/kubernetes/pki/ca.key \
 -CAcreateserial \
 -out registry/docker-registry.crt \
 -extfile registry/openssl.cnf \
 -extensions v3_req

验证 registry 证书

 openssl x509 -text -noout -in registry/docker-registry.crt
Certificate:
...
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Key Usage:
                Digital Signature, Non Repudiation, Key Encipherment
            X509v3 Subject Alternative Name:
                DNS:docker-registry.mokr.cn, DNS:docker-registry.default.svc, DNS:docker-registry.default.svc.cluster.local
...

为 registry 配置 secret 证书

kubectl create secret tls registry-certificates --cert=registry/docker-registry.crt --key=registry/docker-registry.key

创建 registry

kubectl apply -f registry/pvc.yaml

kubectl apply -f registry/deployment.yaml

创建 registry route

 cat > registry/docker-registry-route.yaml <<EOF
kind: Route
apiVersion: route.openshift.io/v1
metadata:
  name: docker-registry
  labels:
    app: docker-registry
spec:
  host: docker-registry.mokr.cn
  tls:
    insecureEdgeTerminationPolicy: Redirect ## None Allow Redirect
    termination: passthrough ## edge passthrough reencrypt
  to:
    kind: Service
    name: docker-registry
    weight: 100
  wildcardPolicy: None
EOF

 kubectl apply -f registry/docker-registry-route.yaml

配置 docker

 vim /etc/docker/daemon.json
{
...
  "registry-mirrors": [
    "https://docker-registry.mokr.cn",
    "https://docker-registry.default.svc:5000",
    "https://docker-registry.default.svc.cluster.local:5000"
  ],
  "insecure-registries": [
    "docker-registry.mokr.cn",
    "docker-registry.default.svc:5000",
    "docker-registry.default.svc.cluster.local:5000"
  ],
...
}

 systemctl restart docker

 docker info
...
 Insecure Registries:
  docker-registry.default.svc.cluster.local:5000
  docker-registry.default.svc:5000
  docker-registry.mokr.cn
  127.0.0.0/8
 Registry Mirrors:
  https://docker-registry.mokr.cn/
  https://docker-registry.default.svc:5000/
  https://docker-registry.default.svc.cluster.local:5000/
 Live Restore Enabled: false

下载 image 测试

docker pull busybox:latest

docker tag busybox:latest docker-registry.default.svc:5000/busybox:latest
docker tag busybox:latest docker-registry.default.svc.cluster.local:5000/busybox:latest
docker tag busybox:latest docker-registry.mokr.cn/default/busybox:latest

docker push docker-registry.default.svc:5000/busybox:latest
docker push docker-registry.default.svc.cluster.local:5000/busybox:latest
docker push docker-registry.mokr.cn/default/busybox:latest

验证 registry

 curl -ik https://docker-registry.mokr.cn/v2/_catalog --resolve 'docker-registry.mokr.cn:443:10.10.34.89' -v
* Added docker-registry.mokr.cn:443:10.10.34.89 to DNS cache
* Hostname docker-registry.mokr.cn was found in DNS cache
*   Trying 10.10.34.89...
* TCP_NODELAY set
* Connected to docker-registry.mokr.cn (10.10.34.89) port 443 (0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=CN; ST=GuangDong; L=ShenZhen; O=Mokr LTD; OU=OPS
*  start date: Apr 11 15:05:20 2020 GMT
*  expire date: Apr 11 15:05:20 2021 GMT
*  issuer: CN=kubernetes
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x556a671559a0)
> GET /v2/_catalog HTTP/2
> Host: docker-registry.mokr.cn
> User-Agent: curl/7.58.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200
HTTP/2 200
< content-type: application/json; charset=utf-8
content-type: application/json; charset=utf-8
< docker-distribution-api-version: registry/2.0
docker-distribution-api-version: registry/2.0
< x-content-type-options: nosniff
x-content-type-options: nosniff
< content-length: 47
content-length: 47
< date: Sat, 11 Apr 2020 15:57:22 GMT
date: Sat, 11 Apr 2020 15:57:22 GMT

<
{"repositories":["busybox","default/busybox"]}
* Connection 0 to host docker-registry.mokr.cn left intact

清理 registry images

 登录 docker-registry
 kubectl exec -it $(kubectl get pods -l k8s-app=docker-registry -o jsonpath={.items[0].metadata.name}) sh

/  registry garbage-collect /etc/docker/registry/config.yml --delete-untagged=true

安装部署 cert-manager

下载安装脚本

mkdir -p cert-manager

curl -L https://github.com/jetstack/cert-manager/releases/download/v0.14.1/cert-manager.yaml -o cert-manager/cert-manager.yaml

sed -i 's/namespace: "cert-manager"/namespace: kube-system/g' cert-manager/cert-manager.yaml

sed -i 's/namespace: cert-manager/namespace: kube-system/g' cert-manager/cert-manager.yaml

sed -i 's/secret: "cert-manager/secret: kube-system/g' cert-manager/cert-manager.yaml

sed -i 's/secret: cert-manager/secret: kube-system/g' cert-manager/cert-manager.yaml

注释 5878 - 5882 行,关闭
sed -i '5878,5882s/^//g' cert-manager/cert-manager.yaml

执行安装

kubectl apply -f cert-manager/cert-manager.yaml

检查安装

 kubectl get pods -n kube-system | grep cert-manager
cert-manager-557f8d6944-zr5jh              1/1     Running   0          2m1s
cert-manager-cainjector-6999bdd97-nfsrn    1/1     Running   0          2m1s
cert-manager-webhook-c579c9f47-g6rd5       1/1     Running   0          2m1s

 kubectl get crd -o custom-columns=crd-name:.metadata.name|grep cert-manager
certificaterequests.cert-manager.io
certificates.cert-manager.io
challenges.acme.cert-manager.io
clusterissuers.cert-manager.io
issuers.cert-manager.io
orders.acme.cert-manager.io

本博客所有文章除特别声明外,均采用: 署名-非商业性使用-禁止演绎 4.0 国际协议,转载请保留原文链接及作者。

Ansible简明指北 上一篇
ansible 部署zk、kafka、nacos集群 下一篇

 目录


买个卤蛋,吃根冰棒