🚀 部署 Kubernetes
Kubernetes,作为一个领先的容器编排工具,支持在各种环境中进行部署,满足不同用户的需求。
1. 🌍 部署环境
Kubernetes 支持在多种环境中部署:
-
💻 本地主机:
- Ubuntu
- Debian
- CentOS
- Fedora
-
☁️ 云服务:
- 如 AWS, Azure, Google Cloud 等
2. 🛠️ 部署方式
你可以选择以下几种主流的部署方式:
-
🟢 kubeadm:
Kubeadm 是 Kubernetes 官方提供的用于快速部署 Kubernetes 集群的工具。它帮助你引导一个最小可行的 Kubernetes 集群,并且能够在现有的集群上进行扩展。 -
🐳 Docker Desktop:
对于开发者来说,Docker Desktop 是一个在本地开发环境中快速部署 Kubernetes 的简单方法。只需一键,你就可以在 Docker Desktop 中启用 Kubernetes。 -
🌱 k3s:
k3s 是一个轻量级的 Kubernetes 发行版,专为在资源受限的环境中运行而设计,如 IoT 设备、边缘计算等。
🎢 使用 kubeadm 部署 Kubernetes (CRI 使用 containerd)
kubeadm 提供了一种简便的方法,通过 kubeadm init
和 kubeadm join
命令来快速创建 Kubernetes 集群。
1. 📦 安装 containerd
首先,你需要安装 containerd:
- 为 Debian 系统:
$ sudo apt install containerd.io
- 为 RHEL 系统:
$ sudo yum install containerd.io
2. 🛠️ 配置 containerd
接下来,需要配置 containerd。
- 新建 /etc/systemd/system/cri-containerd.service 文件并配置相关内容。
[Unit]
Description=containerd container runtime for kubernetes
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd --config //etc/cri-containerd/config.toml
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
- 新建 /etc/cri-containerd/config.toml 作为 containerd 的配置文件。
version = 2
# persistent data location
root = "/var/lib/cri-containerd"
# runtime state information
state = "/run/cri-containerd"
plugin_dir = ""
disabled_plugins = []
required_plugins = []
# set containerd's OOM score
oom_score = 0
[grpc]
address = "/run/cri-containerd/cri-containerd.sock"
tcp_address = ""
tcp_tls_cert = ""
tcp_tls_key = ""
# socket uid
uid = 0
# socket gid
gid = 0
max_recv_message_size = 16777216
max_send_message_size = 16777216
[debug]
address = ""
format = "json"
uid = 0
gid = 0
level = ""
[metrics]
address = "127.0.0.1:1338"
grpc_histogram = false
[cgroup]
path = ""
[timeouts]
"io.containerd.timeout.shim.cleanup" = "5s"
"io.containerd.timeout.shim.load" = "5s"
"io.containerd.timeout.shim.shutdown" = "3s"
"io.containerd.timeout.task.state" = "2s"
[plugins]
[plugins."io.containerd.gc.v1.scheduler"]
pause_threshold = 0.02
deletion_threshold = 0
mutation_threshold = 100
schedule_delay = "0s"
startup_delay = "100ms"
[plugins."io.containerd.grpc.v1.cri"]
disable_tcp_service = true
stream_server_address = "127.0.0.1"
stream_server_port = "0"
stream_idle_timeout = "4h0m0s"
enable_selinux = false
selinux_category_range = 1024
sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.5"
stats_collect_period = 10
# systemd_cgroup = false
enable_tls_streaming = false
max_container_log_line_size = 16384
disable_cgroup = false
disable_apparmor = false
restrict_oom_score_adj = false
max_concurrent_downloads = 3
disable_proc_mount = false
unset_seccomp_profile = ""
tolerate_missing_hugetlb_controller = true
disable_hugetlb_controller = true
ignore_image_defined_volumes = false
[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "overlayfs"
default_runtime_name = "runc"
no_pivot = false
disable_snapshot_annotations = false
discard_unpacked_layers = false
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
pod_annotations = []
container_annotations = []
privileged_without_host_devices = false
base_runtime_spec = ""
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
# SystemdCgroup enables systemd cgroups.
SystemdCgroup = true
# BinaryName is the binary name of the runc binary.
# BinaryName = "runc"
# BinaryName = "crun"
# NoPivotRoot disables pivot root when creating a container.
# NoPivotRoot = false
# NoNewKeyring disables new keyring for the container.
# NoNewKeyring = false
# ShimCgroup places the shim in a cgroup.
# ShimCgroup = ""
# IoUid sets the I/O's pipes uid.
# IoUid = 0
# IoGid sets the I/O's pipes gid.
# IoGid = 0
# Root is the runc root directory.
Root = ""
# CriuPath is the criu binary path.
# CriuPath = ""
# CriuImagePath is the criu image path
# CriuImagePath = ""
# CriuWorkPath is the criu work path.
# CriuWorkPath = ""
[plugins."io.containerd.grpc.v1.cri".cni]
bin_dir = "/opt/cni/bin"
conf_dir = "/etc/cni/net.d"
max_conf_num = 1
conf_template = ""
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/cri-containerd/certs.d"
[plugins."io.containerd.grpc.v1.cri".registry.headers]
# Foo = ["bar"]
[plugins."io.containerd.grpc.v1.cri".image_decryption]
key_model = ""
[plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming]
tls_cert_file = ""
tls_key_file = ""
[plugins."io.containerd.internal.v1.opt"]
path = "/opt/cri-containerd"
[plugins."io.containerd.internal.v1.restart"]
interval = "10s"
[plugins."io.containerd.metadata.v1.bolt"]
content_sharing_policy = "shared"
[plugins."io.containerd.monitor.v1.cgroups"]
no_prometheus = false
[plugins."io.containerd.runtime.v2.task"]
platforms = ["linux/amd64"]
[plugins."io.containerd.service.v1.diff-service"]
default = ["walking"]
[plugins."io.containerd.snapshotter.v1.devmapper"]
root_path = ""
pool_name = ""
base_image_size = ""
async_remove = false
3. 🚀 安装 kubelet, kubeadm, kubectl, cri-tools, kubernetes-cni
- 对于 Ubuntu/Debian:
# 添加源并安装
$ apt-get update && apt-get install -y apt-transport-https
$ curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
$ cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
$ apt-get update
$ apt-get install -y kubelet kubeadm kubectl
- 对于 CentOS/Fedora:
# 添加源并安装
$ cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
$ sudo yum install -y kubelet kubeadm kubectl
4. ⚙️ 修改内核的运行参数
执行以下命令来修改内核的运行参数。
$ cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
# 应用配置
$ sysctl --system
5. 🛠️ 配置 kubelet
要配置 kubelet,你需要修改 kubelet.service 文件。具体步骤如下:
1. 📝 修改 kubelet.service 文件
在 /etc/systemd/system/kubelet.service.d/10-proxy-ipvs.conf
路径下创建或修改文件,加入以下内容:
# 启用 ipvs 相关内核模块
[Service]
ExecStartPre=-/sbin/modprobe ip_vs
ExecStartPre=-/sbin/modprobe ip_vs_rr
ExecStartPre=-/sbin/modprobe ip_vs_wrr
ExecStartPre=-/sbin/modprobe ip_vs_sh
这些命令将在 kubelet 服务启动之前加载 ipvs 相关的内核模块。
2. 🔄 应用配置
为了使这些更改生效,你需要重新加载 systemd 的配置。执行以下命令:
$ sudo systemctl daemon-reload
这条命令会使 systemd 重新读取修改后的配置文件。
6. 🚀 部署
🖥️ Master 节点部署
-
启用 cri-containerd 服务:
$ systemctl enable cri-containerd
-
启动 cri-containerd 服务:
$ systemctl start cri-containerd
-
初始化 Kubernetes:
使用 kubeadm 初始化 Kubernetes 集群:
$ sudo kubeadm init \ --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \ --pod-network-cidr 10.244.0.0/16 \ --cri-socket /run/cri-containerd/cri-containerd.sock \ --v 5 \ --ignore-preflight-errors=all
注意:
--pod-network-cidr 10.244.0.0/16
参数与后续 CNI 插件有关。这里以 flannel 为例。如果你打算部署其他类型的网络插件,请更改此参数。在执行过程中,可能会出现错误,例如缺少依赖包。如果有提示,请根据提示安装相应的包。
执行成功后, 你会看到以下输出:
... [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy ...
这意味着你的 Kubernetes 控制平面已成功初始化!
-
开始使用集群:
为了开始使用你的集群,你需要执行以下操作:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
接下来, 你应该为集群部署一个 pod 网络。
🖥️ Node (工作节点) 部署
如果你有其他机器希望加入到这个集群作为工作节点, 请按照以下步骤进行:
-
在另一台机器上重复 “Master 节点部署” 的前两个步骤。
-
加入集群:
根据主节点的提示,加入到集群:
$ kubeadm join 192.168.199.100:6443 \ --token cz81zt.orsy9gm9v649e5lf \ --discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe \ --cri-socket /run/cri-containerd/cri-containerd.sock
这样, 你的工作节点就成功地加入了 Kubernetes 集群!
7. 🌐 查看服务
🛠️ 查看运行的容器
首先, 我们可以通过 crictl
工具查看实际运行的容器:
CONTAINER_RUNTIME_ENDPOINT=/run/cri-containerd/cri-containerd.sock crictl ps -a
📋 服务分类
1. 主节点服务 (Master Node Services)
🔹 apiserver
- 描述: 是整个系统的对外接口。
- 功能: 提供 RESTful 的方式供客户端和其它组件调用。
# 查看 apiserver 的状态和日志
kubectl get pods -n kube-system | grep apiserver
kubectl logs -n kube-system <apiserver-pod-name>
🔹 scheduler
- 描述: 负责资源的调度。
- 功能: 根据需要,分配某个 pod 到某个节点上。
# 查看 scheduler 的状态和日志
kubectl get pods -n kube-system | grep scheduler
kubectl logs -n kube-system <scheduler-pod-name>
🔹 controller-manager
- 描述: 负责管理各种控制器。
- 功能:
- endpoint-controller: 刷新服务和 pod 的关联信息。
- replication-controller: 维护某个 pod 的副本数量为配置的数值。
# 查看 controller-manager 的状态和日志
kubectl get pods -n kube-system | grep controller-manager
kubectl logs -n kube-system <controller-manager-pod-name>
2. 工作节点服务 (Worker Node Services)
🔹 proxy
- 描述: 为 pod 上的服务提供访问的代理。
# 查看 proxy 的状态和日志
kubectl get pods -n kube-system | grep proxy
kubectl logs -n kube-system <proxy-pod-name>
3. 其它服务
🔹 Etcd
- 描述: 是所有 Kubernetes 状态的存储数据库。
# 查看 etcd 的状态和日志
kubectl get pods -n kube-system | grep etcd
kubectl logs -n kube-system <etcd-pod-name>
8. 📡 部署 CNI
- 选择一个 CNI 插件并部署。这里以 flannel 为例。
🔧 配置 kubectl
首先,将 Kubernetes 集群的配置文件复制到 ~/.kube/config
,这样可以方便地使用 kubectl
命令与集群进行交互。使用以下命令来复制配置文件:
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
👀 查看已部署的服务
使用以下命令可以查看已经部署的服务和应用:
kubectl get all -A
这会列出所有的资源,包括 pods、services、deployments 等等。可以通过这些资源来管理和监控集群中的应用程序。
🌐 部署网络插件 (CNI 插件)
-
检查 podCIDR 设置
$ kubectl get node -o yaml | grep CIDR # 输出 podCIDR: 10.244.0.0/16 podCIDRs:
-
Kubernetes 集群需要网络插件来使不同的 Pod 之间可以互相通信。一种常见的网络插件是 Flannel。可以使用以下步骤来部署 Flannel 网络插件:
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.11.0/Documentation/kube-flannel.yml
-
请注意,如果您使用的是单节点集群(例如使用 kubeadm 部署的),默认情况下,主节点不会运行 pod。您可以使用以下命令来解除此限制:
kubectl taint nodes --all node-role.kubernetes.io/master-
这会允许主节点运行 pod。
9. 📚 参考文档
☁️ Docker Desktop
在 Docker Desktop 上使用 Kubernetes 可以提供便捷的本地 Kubernetes 集群。以下是在 Docker Desktop 上启用和测试 Kubernetes 的步骤:
⚡️ 获取 k8s.gcr.io 镜像
由于国内拉取不到 k8s.gcr.io 镜像,我们可以使用开源项目 AliyunContainerService/k8s-for-docker-desktop 来获取所需的镜像。
🏁 启用 Kubernetes
-
打开 Docker Desktop 应用程序。
-
点击菜单栏中的 Docker 图标,选择 “Preferences”(首选项)。
-
在首选项窗口中,选择 “Kubernetes” 选项卡。
-
勾选 “Enable Kubernetes” 复选框。
-
点击 “Apply & Restart”(应用并重启)按钮。Docker Desktop 将会开始启动 Kubernetes 集群。
-
等待一段时间,直到状态栏中的 “Kubernetes is running”(Kubernetes 运行中)消息出现。这表示 Kubernetes 集群已成功启动。
🧪 测试 Kubernetes
-
打开终端(命令行界面)。
-
运行以下命令来检查 Kubernetes 的版本信息:
kubectl version
如果成功输出版本信息,则表示 Kubernetes 已经在 Docker Desktop 上启用并运行。
现在,您已经成功在 Docker Desktop 上启用了 Kubernetes,并可以开始使用 Kubernetes 集群进行本地开发和测试。您可以使用 kubectl
命令管理和操作 Kubernetes 资源,以及部署和运行容器化应用程序。
🧲 部署 kubernetes 集群
- 可以参考 opsnull/follow-me-install-kubernetes-cluster 项目一步步部署 kubernetes 集群。
🎉 部署 Kubernetes Dashboard
-
Kubernetes Dashboard 是一个基于 Web 的 Kubernetes 用户界面,用于可视化地管理和监视 Kubernetes 集群。以下是在 Kubernetes 集群上部署和访问 Kubernetes Dashboard 的步骤:
🚀 部署 Kubernetes Dashboard
执行以下命令即可部署 Kubernetes Dashboard:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
这将创建 Kubernetes Dashboard 所需的所有资源。
🌐 访问 Kubernetes Dashboard
要访问 Kubernetes Dashboard,请执行以下步骤:
-
打开终端,并运行以下命令来启动代理:
kubectl proxy
这将在本地主机的 8001 端口上启动一个代理,允许您通过代理访问 Kubernetes API。
-
在浏览器中打开以下 URL 以访问 Kubernetes Dashboard:
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
请注意,此 URL 是通过代理访问 Kubernetes Dashboard 的地址。
🔑 登录 Kubernetes Dashboard
Kubernetes Dashboard 目前仅支持使用 Bearer 令牌进行身份验证。以下是如何创建并使用 Bearer 令牌登录的步骤:
-
创建一个名为
dashboard-admin
的 ServiceAccount 和 ClusterRoleBinding,授予其集群管理员角色。执行以下命令:kubectl create sa dashboard-admin -n kube-system kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
-
获取
dashboard-admin
ServiceAccount 的令牌并保存到环境变量中。执行以下命令:ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}') DASHBOARD_LOGIN_TOKEN=$(kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}')
-
打印出
DASHBOARD_LOGIN_TOKEN
的值:echo ${DASHBOARD_LOGIN_TOKEN}
-
将
DASHBOARD_LOGIN_TOKEN
的值粘贴到 Kubernetes Dashboard 登录页面,即可成功登录。
现在,您已经成功部署和访问了 Kubernetes Dashboard,并可以使用该界面来管理和监视您的 Kubernetes 集群。请妥善保管令牌,以确保安全性。
💚 Kubernetes 命令行工具
Kubernetes 命令行工具 kubectl
是与 Kubernetes 集群进行交互的主要工具。以下是一些常用 kubectl
命令及其功能的详解:
-
get: 用于显示一个或多个资源的信息。示例:
kubectl get pods # 获取所有 Pods 的列表 kubectl get services # 获取所有 Services 的列表
-
describe: 用于显示资源的详细信息。示例:
kubectl describe pod <pod-name> # 获取特定 Pod 的详细信息
-
create: 用于从文件或标准输入创建资源。示例:
kubectl create -f pod.yaml # 从 YAML 文件创建一个 Pod
-
update: 用于从文件或标准输入更新资源。示例:
kubectl apply -f pod-updated.yaml # 从更新后的 YAML 文件更新一个 Pod
-
delete: 用于删除资源。可以通过文件名、标准输入、资源名或者 label selector 删除资源。示例:
kubectl delete pod <pod-name> # 删除特定 Pod
-
log: 用于查看 Pod 中一个容器的日志。示例:
kubectl logs <pod-name> -c <container-name> # 查看特定容器的日志
-
exec: 用于在容器内部执行命令。示例:
kubectl exec -it <pod-name> -- /bin/bash # 进入容器的命令行终端
-
port-forward: 用于将本地端口转发到 Pod。示例:
kubectl port-forward <pod-name> 8080:80 # 将本地 8080 端口映射到 Pod 的 80 端口
-
proxy: 用于为 Kubernetes API server 启动代理服务器,以便访问集群内部资源。示例:
kubectl proxy # 启动代理服务器,允许通过 API 访问集群资源
-
run: 用于在集群中使用指定镜像启动容器。示例:
kubectl run nginx --image=nginx # 启动一个名为 "nginx" 的容器
-
expose: 用于将 replication controller、service 或 pod 暴露为新的 Kubernetes service。示例:
kubectl expose deployment my-deployment --type=NodePort --port=80 # 将 Deployment 暴露为 NodePort 服务
-
label: 用于更新资源的 label,以便对资源进行分类和选择。示例:
kubectl label pod <pod-name> app=backend # 为 Pod 添加一个标签
-
config: 用于修改 Kubernetes 配置文件。示例:
kubectl config view # 查看当前配置文件内容
-
cluster-info: 用于显示集群信息,包括 API server 地址等。示例:
kubectl cluster-info # 显示集群信息
-
api-versions: 以 “组/版本” 的格式输出服务端支持的 API 版本。示例:
kubectl api-versions # 列出支持的 API 版本
-
version: 输出服务端和客户端的版本信息。示例:
kubectl version # 查看 Kubernetes 服务端和客户端版本信息
-
help: 显示各个命令的帮助信息。示例:
kubectl get --help # 查看 `get` 命令的帮助信息
这些是 kubectl
常用命令及其功能的简要介绍。kubectl
是 Kubernetes 管理和操作的重要工具,您可以根据需要使用不同的命令来管理 Kubernetes 集群。