Kubernetes 入门实战 Part2

17 多节点的 Kubernetes 集群

在腾讯云 TencentOS Server 3.1 (TK4) 下测试:

  • master SA3.MEDIUM4 2 核 4GB 5Mbps
  • worker S5.SMALL2 1 核 2GB 1Mbps
  • worker S5.SMALL2 1 核 2GB 1Mbps
代码语言:javascript
复制
# 修改源 https://mirrors.cloud.tencent.com/
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.cloud.tencent.com/repo/centos7_base.repo
yum clean all
yum makecache

install docker

yum remove docker
docker-client
docker-client-latest
docker-common
docker-latest
docker-latest-logrotate
docker-logrotate
docker-engine

yum install -y yum-utils

yum-config-manager
--add-repo
https://download.docker.com/linux/centos/docker-ce.repo

yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

systemctl start docker
docker -v
docker run hello-world

一些准备工作:

代码语言:javascript
复制
# 改主机名
vi /etc/hostname

reboot

代码语言:javascript
复制
# 把 cgroup 的驱动程序改成 systemd

使用 Docker 作为 Kubernetes 的底层支持

cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF

systemctl enable docker
systemctl daemon-reload
systemctl restart docker
docker version

代码语言:javascript
复制
# https://kubernetes.io/zh-cn/docs/setup/production-environment/container-runtimes/

转发 IPv4 并让 iptables 看到桥接流量

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

check

lsmod | grep br_netfilter
lsmod | grep overlay

设置所需的 sysctl 参数,参数在重新启动后保持不变

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

应用 sysctl 参数而不重新启动

sudo sysctl --system

sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

net.bridge.bridge-nf-call-iptables = 1

net.bridge.bridge-nf-call-ip6tables = 1

net.ipv4.ip_forward = 1

代码语言:javascript
复制
# 关闭 Linux 的 swap 分区

swapoff -a
sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab

代码语言:javascript
复制
# https://developer.aliyun.com/mirror/kubernetes
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.cloud.tencent.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
EOF

yum clean all
yum makecache

将 SELinux 设置为 permissive 模式(相当于将其禁用)

setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

新版本搞不定

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes --nogpgcheck

yum --showduplicate list kubelet
yum install -y kubelet-1.23.16-0 kubeadm-1.23.16-0 kubectl-1.23.16-0 --disableexcludes=kubernetes --nogpgcheck

systemctl enable --now kubelet

kubeadm version
kubectl version --output=yaml
kubelet --version

下载 Kubernetes 组件镜像:

代码语言:javascript
复制
# kubeadm config images list
kubeadm config images list --kubernetes-version v1.23.16

安装 Master 节点:

代码语言:javascript
复制
vim /etc/containerd/config.toml
#disabled_plugins = ["cri"]

systemctl enable containerd
systemctl restart containerd
systemctl status containerd

systemctl enable kubelet.service
systemctl restart kubelet
systemctl status kubelet

containerd config default > /etc/containerd/config.toml

yum install -y nc
nc 127.0.0.1 6443

kubeadm init -h
kubeadm reset -f
rm -rf ~/.kube/config

kubeadm init
--image-repository=registry.aliyuncs.com/google_containers
--pod-network-cidr=10.10.0.0/16
--kubernetes-version=v1.23.16
--v=9

Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:

https://kubernetes.io/docs/concepts/cluster-administration/addons/

代码语言:javascript
复制
# success

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

export KUBECONFIG=/etc/kubernetes/admin.conf

代码语言:javascript
复制
kubectl get node

NAME STATUS ROLES AGE VERSION

master NotReady control-plane,master 2m4s v1.23.16

代码语言:javascript
复制
# dubug

systemctl restart docker
systemctl restart kubelet
systemctl restart containerd
journalctl -xeu kubelet
crictr ps -a
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock ps -a | grep kube | grep -v pause

kubectl get pods -n kube-system
kubectl describe pods -n kube-system

代码语言:javascript
复制
# Flannel 网络插件 https://github.com/flannel-io/flannel/tree/master

curl https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml --output kube-flannel.yml

net-conf.json: |

{

"Network": "10.10.0.0/16",

"Backend": {

"Type": "vxlan"

}

}

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
kubectl get node

NAME STATUS ROLES AGE VERSION

master Ready control-plane,master 14h v1.23.16

代码语言:javascript
复制
# show join command in control-plane

kubeadm token create --print-join-command

work join; 云服务记得开放入站端口

telnet 172.21.0.5 6443
systemctl enable kubelet.service
kubeadm join 172.21.0.5:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx --v=9

check in control-plane

kubectl get nodes

NAME STATUS ROLES AGE VERSION

master Ready control-plane,master 14h v1.23.16

vm-0-9-centos Ready <none> 3m27s v1.23.16

代码语言:javascript
复制
# run nginx

kubectl run ngx --image=nginx:alpine
kubectl get pod -o wide

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES

ngx 1/1 Running 0 52m 10.10.1.2 woker01 <none> <none>

18 Deployment 部署应用

“单一职责”和“对象组合”。既然 Pod 管理不了自己,那么我们就再创建一个新的对象,由它来管理 Pod,采用和 Job/CronJob 一样的形式——“对象套对象”。

代码语言:javascript
复制
kubectl api-resources

export out="--dry-run=client -o yaml"
kubectl create deploy ngx-dep --image=nginx:alpine $out > ngx-dep.yml
vim ngx-dep.yml

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: ngx-dep
name: ngx-dep
spec:

定义了 Pod 的“期望数量”,Kubernetes 会自动维护 Pod 数量到正常水平

replicas: 2

定义了基于 labels 筛选 Pod 的规则,它必须与 template 里 Pod 的 labels 一致

selector:
matchLabels:
app: ngx-dep
strategy: {}
template:
metadata:
creationTimestamp: null
# 贴标签
labels:
app: ngx-dep
spec:
containers:
- image: nginx:alpine
name: nginx
resources: {}
status: {}

Deployment 实际上并不“持有”Pod 对象,它只是帮助 Pod 对象能够有足够的副本数量运行。

通过标签这种设计,Kubernetes 就解除了 Deployment 和模板里 Pod 的强绑定,把组合关系变成了“弱引用”。

代码语言:javascript
复制
# replicas: 2
kubectl apply -f ngx-dep.yml

kubectl get deploy

NAME READY UP-TO-DATE AVAILABLE AGE

ngx-dep 2/2 2 2 57s

kubectl get pod

NAME READY STATUS RESTARTS AGE

ngx-dep-bfbb5f64b-96scb 1/1 Running 0 3m20s

ngx-dep-bfbb5f64b-qnzbh 1/1 Running 0 3m20s

  • READY:运行的 Pod 数量,当前数量/期望数量。
  • UP-TO-DATE:当前已经更新到最新状态的 Pod 数量。
  • AVAILABLE:不仅要求已经运行,还必须是健康状态,能够正常对外提供服务,它才是我们最关心的 Deployment 指标。
  • AGE:从创建到现在所经过的时间。
代码语言:javascript
复制
# 测试自启恢复

kubectl delete pod ngx-dep-bfbb5f64b-qnzbh
kubectl get pod

NAME READY STATUS RESTARTS AGE

ngx-dep-bfbb5f64b-7n724 1/1 Running 0 33s

ngx-dep-bfbb5f64b-96scb 1/1 Running 0 4m52s

测试伸缩

kubectl scale --replicas=5 deploy ngx-dep
kubectl get pod

NAME READY STATUS RESTARTS AGE

ngx-dep-bfbb5f64b-7n724 1/1 Running 0 77s

ngx-dep-bfbb5f64b-7xhbs 1/1 Running 0 7s

ngx-dep-bfbb5f64b-96scb 1/1 Running 0 5m36s

ngx-dep-bfbb5f64b-97qp5 1/1 Running 0 7s

ngx-dep-bfbb5f64b-vjn4q 1/1 Running 0 7s

代码语言:javascript
复制
# 筛选标签 ==、!=、in、notin

kubectl get pod -l app=nginx
kubectl get pod -l 'app in (ngx, nginx, ngx-dep)'

19 DaemonSet 看门狗

在 Deployment 看来,Pod 的运行环境与功能是无关的,只要 Pod 的数量足够,应用程序应该会正常工作。

有些场景下,要在集群里的每个节点上都运行 Pod,也就是说 Pod 的数量与节点数量保持同步。防止在集群里漂移。

DaemonSet 的目标是在集群的每个节点上运行且仅运行一个 Pod。

代码语言:javascript
复制
kubectl api-resources
代码语言:javascript
复制
# export out="--dry-run=client -o yaml"

kubectl create deploy redis-ds --image=redis:5-alpine $out

kind modify DaemonSet, delete spec.replicas

https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/daemonset/

vim redis-ds.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: redis-ds
labels:
app: redis-ds
spec:

和 deplayment 比没有 replicas

selector:
matchLabels:
name: redis-ds
template:
metadata:
labels:
name: redis-ds
spec:
containers:
- image: redis:5-alpine
name: redis
ports:
- containerPort: 6379

代码语言:javascript
复制
kubectl apply -f redis-ds.yml
kubectl get ds

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE

redis-ds 2 2 2 2 2 <none> 30m

kubectl get pod -o wide

两个 worker 的场景

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES

redis-ds-9r96k 1/1 Running 0 2m52s 10.10.3.2 woker02 <none> <none>

redis-ds-hdl28 1/1 Running 0 21m 10.10.1.11 woker01 <none> <none>

Master 节点却被排除在外了

污点(taint)作用也是给节点“贴标签”。容忍度(toleration)Pod 能否“容忍”污点。

代码语言:javascript
复制
kubectl describe node master

Taints: node-role.kubernetes.io/master:NoSchedule

污点会拒绝 Pod 调度到本节点上运行

kubectl describe node woker01

Taints: <none>

代码语言:javascript
复制
# - 出掉 master 污点

kubectl taint node master node-role.kubernetes.io/master:NoSchedule-

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE

redis-ds 3 3 3 3 3 <none> 31m

代码语言:javascript
复制
# Pod 添加 tolerations

kubectl explain ds.spec.template.spec.tolerations

vim redis-ds-t.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: redis-ds-t
labels:
app: redis-ds-t
spec:

和 deplayment 比没有 replicas

selector:
matchLabels:
name: redis-ds-t
template:
metadata:
labels:
name: redis-ds-t
spec:
containers:
- image: redis:5-alpine
name: redis
ports:
- containerPort: 6379
# 容忍 node-role.kubernetes.io/master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
operator: Exists

代码语言:javascript
复制
kubectl apply -f redis-ds-t.yml
kubectl get ds

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE

redis-ds 2 2 2 2 2 <none> 41m

redis-ds-t 3 3 3 3 3 <none> 6s

差别在 master

kubectl get pod -o wide

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES

redis-ds-9r96k 1/1 Running 0 23m 10.10.3.2 woker02 <none> <none>

redis-ds-hdl28 1/1 Running 0 42m 10.10.1.11 woker01 <none> <none>

redis-ds-t-4mptv 1/1 Running 0 80s 10.10.3.4 woker02 <none> <none>

redis-ds-t-dpcl8 1/1 Running 0 80s 10.10.1.12 woker01 <none> <none>

redis-ds-t-kdjmn 1/1 Running 0 80s 10.10.0.6 master <none> <none>

https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/

静态 Pod:

代码语言:javascript
复制
ll -a /etc/kubernetes/manifests

-rw------- 1 root root 2274 Feb 22 12:47 etcd.yaml

-rw------- 1 root root 3358 Feb 22 12:47 kube-apiserver.yaml

-rw------- 1 root root 2878 Feb 22 12:47 kube-controller-manager.yaml

-rw------- 1 root root 1465 Feb 22 12:47 kube-scheduler.yaml

Kubernetes 的 4 个核心组件 apiserver、etcd、scheduler、controller-manager 原来都以静态 Pod 的形式存在的,这也是为什么它们能够先于 Kubernetes 集群启动的原因。

kubelet 会定期检查目录里的文件。

代码语言:javascript
复制
# flannel 就是一个 DaemonSet

kubectl get ns
kubectl get ds -n kube-flannel

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE

kube-flannel-ds 3 3 3 3 3 <none> 3h54m

20 Service 服务发现

由 kube-proxy 控制的四层负载均衡,在 TCP/IP 协议栈上转发流量。

Pod 的生命周期很短暂,会不停地创建销毁,所以就需要用 Service 来实现负载均衡,它由 Kubernetes 分配固定的 IP 地址,能够屏蔽后端的 Pod 变化。

代码语言:javascript
复制
export out="--dry-run=client -o yaml"

kubectl expose deploy ngx-dep --port=80 --target-port=80 $ou

代码语言:javascript
复制
# vim ngx-svc.yml
apiVersion: v1
kind: Service
metadata:
name: ngx-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: ngx-dep
status:
loadBalancer: {}


apiVersion: v1
kind: ConfigMap
metadata:
name: ngx-conf
data:
default.conf: |
server {
listen 80;
location / {
default_type text/plain;
return 200
'srv : server_addr:server_port\nhost: hostname\nuri : request_method host request_uri\ndate: $time_iso8601\n';
}
}


apiVersion: apps/v1
kind: Deployment
metadata:
name: ngx-dep
spec:
replicas: 2
selector:
matchLabels:
app: ngx-dep
template:
metadata:
labels:
app: ngx-dep
spec:
volumes:
- name: ngx-conf-vol
configMap:
name: ngx-conf
containers:
- image: nginx:alpine
name: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: ngx-conf-vol

代码语言:javascript
复制
kubectl apply -f ngx-svc.yml
kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5h10m

ngx-svc ClusterIP 10.109.131.132 <none> 80/TCP 35s

虚地址 10.109.131.132

kubectl describe svc ngx-svc

Name: ngx-svc

Namespace: default

Labels: <none>

Annotations: <none>

Selector: app=ngx-dep

Type: ClusterIP

IP Family Policy: SingleStack

IP Families: IPv4

IP: 10.109.131.132

IPs: 10.109.131.132

Port: <unset> 80/TCP

TargetPort: 80/TCP

Endpoints: 10.10.1.13:80,10.10.3.5:80

Session Affinity: None

Events: <none>

kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
ngx-dep-6796688696-cwm8f 1/1 Running 0 2m4s 10.10.3.5 woker02
ngx-dep-6796688696-khjnv 1/1 Running 0 2m2s 10.10.1.13 woker01

same Endpoints

因为 Service、 Pod 的 IP 地址都是 Kubernetes 集群的内部网段

所以我们需要用 kubectl exec 进入到 Pod 内部

kubectl exec -it ngx-dep-6796688696-cwm8f -- sh
curl 10.109.131.132

srv : 10.10.3.5:80

host: ngx-dep-6796688696-cwm8f

uri : GET 10.109.131.132 /

date: 2023-02-22T10:09:49+00:00

curl 10.109.131.132

srv : 10.10.1.13:80

host: ngx-dep-6796688696-khjnv

uri : GET 10.109.131.132 /

date: 2023-02-22T10:09:50+00:00

测试恢复

kubectl delete pod ngx-dep-6796688696-khjnv
kubectl describe svc ngx-svc

Endpoints: 10.10.1.14:80,10.10.3.5:80

之前是 10.10.1.13:80,10.10.3.5:80

测试扩容

kubectl scale --replicas=5 deploy ngx-dep
kubectl describe svc ngx-svc

Endpoints: 10.10.1.14:80,10.10.1.15:80,10.10.3.5:80 + 2 more...

Service 对象的域名完全形式是 对象.名字空间.svc.cluster.local,但很多时候也可以省略后面的部分,直接写 对象.名字空间 甚至 对象名 就足够了,默认会使用对象所在的名字空间(比如这里就是 default)。

代码语言:javascript
复制
# Name:              ngx-svc

Namespace: default

kubectl exec -it ngx-dep-6796688696-cwm8f -- sh
curl ngx-svc

srv : 10.10.3.5:80

host: ngx-dep-6796688696-cwm8f

uri : GET ngx-svc /

date: 2023-02-22T10:19:25+00:00

curl ngx-svc.default

srv : 10.10.3.6:80

host: ngx-dep-6796688696-lpcfs

uri : GET ngx-svc.default /

date: 2023-02-22T10:19:41+00:00

curl ngx-svc.default.svc.cluster.local

srv : 10.10.3.5:80

host: ngx-dep-6796688696-cwm8f

uri : GET ngx-svc.default.svc.cluster.local /

date: 2023-02-22T10:20:04+00:00

Pod 分配了域名:IP 地址.名字空间.pod.cluster.local IP 地址 . 改成 -。

代码语言:javascript
复制
# kubectl explain svc.spec.type

vim ngx-svc.yml

...
type: NodePort

代码语言:javascript
复制
kubectl apply -f ngx-svc.yml
kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5h56m

ngx-svc NodePort 10.109.131.132 <none> 80:30916/TCP 46m

Service 的默认类型是“ClusterIP”,只能在集群内部访问,

如果改成“NodePort”,就会在节点上开启一个随机端口号,让外界也能够访问内部的服务。

curl localhost:30916

srv : 10.10.1.15:80

host: ngx-dep-6796688696-l6skl

uri : GET localhost /

date: 2023-02-22T10:48:32+00:00

21 Ingress 流量总管

Service 本身是没有服务能力的,它只是一些 iptables 规则,真正配置、应用这些规则的实际上是节点里的 kube-proxy 组件。

Ingress 也只是一些 HTTP 路由规则的集合,相当于一份静态的描述文件,真正要把这些规则在集群里实施运行,还需要有另外一个东西,这就是 Ingress Controller,它的作用就相当于 Service 的 kube-proxy,能够读取、应用 Ingress 规则,处理、调度流量。

Ingress Class 是插在 Ingress 和 Ingress Controller 中间,作为流量规则和控制器的协调人,解除了 Ingress 和 Ingress Controller 的强绑定关系。

Kubernetes 用户可以转向管理 Ingress Class,用它来定义不同的业务逻辑分组,简化 Ingress 规则的复杂度。

代码语言:javascript
复制
export out="--dry-run=client -o yaml"

kubectl create ing ngx-ing --rule="ngx.test/=ngx-svc:80" --class=ngx-ink $out

代码语言:javascript
复制
# vim ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: ngx-ing
spec:
ingressClassName: ngx-ink
rules:
- host: ngx.test
http:
# 路径的匹配方式
paths:
- backend:
service:
name: ngx-svc
port:
number: 80
path: /
# 精确匹配(Exact)或前缀匹配(Prefix)
pathType: Exact
status:
loadBalancer: {}


apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: ngx-ink
spec:
controller: nginx.org/ingress-controller

代码语言:javascript
复制
kubectl apply -f ingress.yml

NAME CONTROLLER PARAMETERS AGE

ngx-ink nginx.org/ingress-controller <none> 15s

kubectl get ing

NAME CLASS HOSTS ADDRESS PORTS AGE

ngx-ing ngx-ink ngx.test 80 84s

kubectl describe ing ngx-ing

Name: ngx-ing

Labels: <none>

Namespace: default

Address:

Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)

Rules:

Host Path Backends

---- ---- --------

ngx.test

/ ngx-svc:80 (10.10.1.14:80,10.10.1.15:80)

Annotations: <none>

Events: <none>

在 Kubernetes 里使用 Ingress Controller:

https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-manifests/

代码语言:javascript
复制
git clone https://github.com/nginxinc/kubernetes-ingress.git --branch v3.0.2

cd kubernetes-ingress/deployments

Configure RBAC

为Ingress控制器创建一个命名空间和一个服务账户

kubectl apply -f common/ns-and-sa.yaml

为服务账户创建一个集群角色和集群角色绑定

kubectl apply -f rbac/rbac.yaml

Create Common Resources

为NGINX的默认服务器创建一个带有TLS证书和密钥的秘密

kubectl apply -f common/default-server-secret.yaml

创建一个 config map,用于定制NGINX配置。

kubectl apply -f common/nginx-config.yaml

创建一个IngressClass资源

kubectl apply -f common/ingress-class.yaml

Create Custom Resources

kubectl apply -f common/crds/

vim deployment/nginx-ingress.yaml

args add:

-enable-custom-resources=false

Run the Ingress Controller

kubectl apply -f deployment/nginx-ingress.yaml

check

kubectl get pods --namespace=nginx-ingress

NAME READY STATUS RESTARTS AGE

nginx-ingress-5f98f8f5f9-nnkv7 1/1 Running 0 3m14s

Get Access to the Ingress Controller

kubectl create -f service/nodeport.yaml
kubectl get service -n nginx-ingress

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

nginx-ingress NodePort 10.111.210.52 <none> 80:31754/TCP,443:30188/TCP 5s

代码语言:javascript
复制
# debug

kubectl get IngressClass
kubectl get ing -n nginx-ingress
kubectl get deploy -n nginx-ingress
kubectl get pod -n nginx-ingress -o wide

kubectl describe service -n nginx-ingress -o wide
kubectl describe pod -n nginx-ingress

代码语言:javascript
复制
# 命令kubectl port-forward,它可以直接把本地的端口映射到 Kubernetes 集群的某个 Pod 里
kubectl port-forward -n nginx-ingress nginx-ingress-5f98f8f5f9-nnkv7 8080:80 &

22 玩转 Kubernetes 2

Kubernetes 部署 WordPress:

代码语言:javascript
复制
# vim wp-maria.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: maria-cm
data:
DATABASE: "db"
USER: "wp"
PASSWORD: "123"
ROOT_PASSWORD: "123"


apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: maria-dep
name: maria-dep
spec:
replicas: 1
selector:
matchLabels:
app: maria-dep
template:
metadata:
labels:
app: maria-dep
spec:
containers:
- image: mariadb:10
name: mariadb
ports:
- containerPort: 3306
envFrom:
- prefix: "MARIADB_"
configMapRef:
name: maria-cm


apiVersion: v1
kind: Service
metadata:
labels:
app: maria-dep
name: maria-svc
spec:
ports:
- port: 3306
protocol: TCP
targetPort: 3306
selector:
app: maria-dep

代码语言:javascript
复制
kubectl apply -f wp-maria.yml
kubectl get pod
kubectl get deploy
kubectl get svc
代码语言:javascript
复制
# vim wp-app.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: wp-cm
data:

DNS HOST

HOST: "maria-svc"
USER: "wp"
PASSWORD: "123"
NAME: "db"


apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: wp-dep
name: wp-dep
spec:
replicas: 2
selector:
matchLabels:
app: wp-dep
template:
metadata:
labels:
app: wp-dep
spec:
containers:
- image: wordpress:5
name: wordpress
ports:
- containerPort: 80
envFrom:
- prefix: "WORDPRESS_DB_"
configMapRef:
name: wp-cm


apiVersion: v1
kind: Service
metadata:
labels:
app: wp-dep
name: wp-svc
spec:
ports:
- name: http80
port: 80
protocol: TCP
targetPort: 80
# 指定端口
nodePort: 30088
selector:
app: wp-dep

NodePort

type: NodePort

代码语言:javascript
复制
kubectl apply -f wp-app.yml
kubectl get pod
kubectl get deploy
kubectl get svc

kubectl port-forward service/wp-svc 80:80 --address 0.0.0.0

代码语言:javascript
复制
# vim wp-ing.yml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: wp-ink
spec:
controller: nginx.org/ingress-controller


kubectl create ing wp-ing --rule="wp.test/=wp-svc:80" --class=wp-ink $out

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wp-ing
spec:
ingressClassName: wp-ink
rules:
- host: wp.test
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wp-svc
port:
number: 80

代码语言:javascript
复制
# vim wp-kic-dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wp-kic-dep
namespace: nginx-ingress
spec:
replicas: 1
selector:
matchLabels:
app: wp-kic-dep
template:
metadata:
labels:
app: wp-kic-dep
spec:
# kubectl explain Deployment.spec.template.spec.serviceAccountName
serviceAccountName: nginx-ingress
# kubectl explain Deployment.spec.template.spec.hostNetwork
hostNetwork: true
containers:
- image: nginx/nginx-ingress:3.0.2
imagePullPolicy: IfNotPresent
name: nginx-ingress
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: readiness-port
containerPort: 8081
- name: prometheus
containerPort: 9113
readinessProbe:
httpGet:
path: /nginx-ready
port: readiness-port
periodSeconds: 1
securityContext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
runAsNonRoot: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
args:
# 默认是 nginx
- -ingress-class=wp-ink
- -enable-custom-resources=false
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret


apiVersion: v1
kind: Service
metadata:
name: wp-kic-svc
namespace: nginx-ingress

spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
nodePort: 30080

selector:
app: wp-kic-dep
type: NodePort

代码语言:javascript
复制
kubectl apply -f wp-ing.yml -f wp-kic-dep.yml

kubectl get ing
kubectl get ingressclass
kubectl get pod -n=nginx-ingress
kubectl describe pod -n=nginx-ingress
kubectl get deploy -n=nginx-ingress
kubectl get svc -n=nginx-ingress

代码语言:javascript
复制
# 在服务器上
kubectl get pod -n=nginx-ingress -o=wide

NAME READY STATUS RESTARTS AGE IP NODE

wp-kic-dep-68579bc688-d64zs 1/1 Running 0 10m 172.21.0.9 woker01

curl 172.21.0.9 -H "HOST: wp.test"

代码语言:javascript
复制
# 在服务器外
kubectl port-forward service/wp-kic-svc -n=nginx-ingress 80:80 --address 0.0.0.0

vim /etc/hosts
[master ip] wp.test

游览器访问 wp.test

23 中级篇实操总结

代码语言:javascript
复制
# DaemonSet 模板生成

kubectl create deploy redis-ds --image=redis:5-alpine $out
| sed 's/Deployment/DaemonSet/g' -
| sed -e '/replicas/d' -

References

  • chronolaw/k8s_study | GitHub
  • nginx-ingress-controller Installation with Manifests | nginx.com

– EOF –

  • # kubernetes