惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Register - Security
The Register - Security
云风的 BLOG
云风的 BLOG
U
Unit 42
F
Fortinet All Blogs
The GitHub Blog
The GitHub Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
D
Docker
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Secure Thoughts
Hacker News: Ask HN
Hacker News: Ask HN
Vercel News
Vercel News
S
Security @ Cisco Blogs
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
I
Intezer
MongoDB | Blog
MongoDB | Blog
AI
AI
MyScale Blog
MyScale Blog
Engineering at Meta
Engineering at Meta
Y
Y Combinator Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Proofpoint News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
W
WeLiveSecurity
博客园 - 叶小钗
S
SegmentFault 最新的问题
N
News | PayPal Newsroom
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
D
DataBreaches.Net
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
Spread Privacy
Spread Privacy
H
Help Net Security
美团技术团队
博客园 - 司徒正美
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
K
Kaspersky official blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
V
Vulnerabilities – Threatpost
TaoSecurity Blog
TaoSecurity Blog
N
Netflix TechBlog - Medium
L
Lohrmann on Cybersecurity
J
Java Code Geeks
量子位
Martin Fowler
Martin Fowler
博客园_首页

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
Kubernetes 集群运维实践
微信公众号 · 2019-08-22 · via 陈少文的网站

整理自「开发 Tips」系列,汇总 Kubernetes 集群日常运维中的常见问题与解决方法。

1. Kubectl 配置多个集群

在进行 Kubernetes 相关开发时,通常会涉及多个集群的管理。Kubectl 提供了多集群上下文管理的功能。

通常 Kubectl 的配置信息在 $HOME/.kube/config/etc/kubernetes/admin.conf 。登陆机器,查看集群的配置信息,按照下面的格式进行编辑。

kubeconfig 配置格式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion: v1
kind: Config
preferences: {}

clusters:
  - cluster:
      certificate-authority-data: xxx
      server: xxx
    name: { cluster-name1 }
  - cluster:
      certificate-authority-data: xxx
      server: xxx
    name: { cluster-name2 }

users:
  - name: { user-name1 }
    user: xxx
  - name: { user-name2 }
    user: xxx

contexts:
  - context:
      cluster: { cluster-name1 }
      user: { user-name1 }
    name: { context-name1 }
  - context:
      cluster: { cluster-name2 }
      user: { user-name2 }
    name: { context-name2 }

current-context: { context-name1 }

查看集群

1
kubectl config get-contexts

查看 config 信息

切换集群

1
kubectl config use-context {context-name}

2. helm 提示 cannot get resource “namespaces”

使用 helm 安装应用:

1
2
helm install --name prometheus-operator --namespace=monitoring stable/prometheus-operator
Error: namespaces "monitoring" is forbidden: User "system:serviceaccount:kube-system:default" cannot get resource "namespaces" in API group "" in the namespace "monitoring"

解决办法,添加服务账号:

1
2
3
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'

3. Kubernetes 中给 Node 增加 Role: worker

1
2
3
4
kubectl get nodes
NAME         STATUS   ROLES    AGE    VERSION
i-6fns0nua   Ready    master   6d3h   v1.15.2
i-m69skuyd   Ready    <none>   6d2h   v1.15.2
1
2
kubectl label node i-m69skuyd  node-role.kubernetes.io/worker=
node/i-m69skuyd labeled
1
2
3
4
kubectl get node
NAME         STATUS   ROLES    AGE    VERSION
i-6fns0nua   Ready    master   6d3h   v1.15.2
i-m69skuyd   Ready    worker   6d2h   v1.15.2

4. 删除 Kubernetes 的一个节点

查看当前节点:

1
2
3
4
kubectl get node
NAME         STATUS   ROLES    AGE    VERSION
i-6fns0nua   Ready    master   6d3h   v1.15.2
i-m69skuyd   Ready    worker   6d2h   v1.15.2

迁移 Pod ,禁止调度待删除节点:

1
kubectl drain i-m69skuyd --delete-local-data --force --ignore-daemonsets

删除节点:

1
kubectl delete node i-m69skuyd

5. Kubernetes 上用 Helm 安装 Prometheus

首先需要创建 PV,可以参考第一章节。

然后,执行命令:

1
2
3
4
5
helm install --namespace monitor --name prometheus stable/prometheus \
  --set alertmanager.persistentVolume.storageClass="local" \
  --set server.persistentVolume.storageClass="local"
helm install  --namespace monitor --name grafana stable/grafana \
  --set persistence.storageClassName="local"

其他操作可以参考,在 Minikube 集群上安装 Prometheus

6. 如何重启 Kubernetes 中的 Pod 或服务

  1. 重启 Pod

如果 Pod 关联了副本控制器,直接删除 Pod,Kubernetes 会重新创建 Pod 。

  • 查看 Pod
1
kubectl get pod -n {NAMESPACE}
  • 删除 Pod
1
kubectl delete pod {POD_NAME} -n {NAMESPACE}

另外一种是,使用 replace

1
kubectl replace --force -f pod.yaml

如果没有 pod.yaml 文件,可以直接使用下面的命令:

1
kubectl get pod {POD_NAME} -n {NAMESPACE} -o yaml | kubectl replace --force -f -
  1. 重启 Deployment

将服务的副本数设置为 0,然后恢复原始的副本数。

  • 查看服务
1
kubectl get deployment -n {NAMESPACE}
  • 设置副本数为 0
1
kubectl scale deployment {DEPLOYMENT_NAME} --replicas=0 -n {NAMESPACE}
  • 恢复副本数量
1
kubectl scale deployment {DEPLOYMENT_NAME} --replicas={REPLICAS_NUM} -n {NAMESPACE}

7. 通过 NodePort 的方式,暴露正在运行的服务

在服务没有启动之前,通过修改 yaml 配置,可以暴露服务。当服务已经运行起来之后,可以通过 patch 的方式暴露服务。

  • 查看服务
1
kubectl get service -n {NAMESPACE}
  • 暴露端口访问
1
kubectl patch service {SERVICE_NAME} -p '{"spec":{"type":"NodePort"}}' -n {NAMESPACE}

8. NodePort 服务仅指定 Node 可以访问

通过 NodePort 暴露的服务,在集群外可以使用 Kubernetes 任意 Node IP 加端口的形式访问。kube-proxy 会将访问流量以轮询的方式转发给 service 中的每个 Pod。

但是,发现并不是每一个 Node IP 加端口都可以访问,仅运行 Pod 的 Node 可以。

原因是,任意 Node IP 加端口访问,是通过主机间通信实现的。但是 docker 1.13 版本之后对 iptables 规则进行了改动,默认禁用了 FORWARD 。

查看 iptables 规则:

1
2
3
4
5
iptables -L -n

...
Chain FORWARD (policy DROP)
...

打开全局 FORWARD :

1
iptables -P FORWARD ACCEPT

9. 登陆 Kubernetes 中的容器终端

  • 命令格式
1
kubectl exec -it {POD_NAME} -c {CONTAINER_NAME} -n {NAMESPACE_NAME} sh

如果 Pod 中只有一个 Container,则 -c {CONTAINER_NAME} 参数可以省略。

  • 获取 Pod 名称
1
2
3
kubectl get pod -n monitor

monitor       prometheus-alertmanager-5bc4ccf9df-xmt7c         2/2     Running   6          3d23h
  • 获取 Container 名称
1
2
3
4
kubectl log prometheus-alertmanager-5bc4ccf9df-xmt7c -n monitor

log is DEPRECATED and will be removed in a future version. Use logs instead.
Error from server (BadRequest): a container name must be specified for pod prometheus-alertmanager-5bc4ccf9df-xmt7c, choose one of: [prometheus-alertmanager prometheus-alertmanager-configmap-reload]

提示信息中,[prometheus-alertmanager prometheus-alertmanager-configmap-reload] 就是 Pod 中全部容器列表。

  • 登陆 Container 终端
kubectl exec -it prometheus-alertmanager-5bc4ccf9df-xmt7c  -c prometheus-alertmanager -n monitor sh

10. 批量删除 PVC

1
2
kubectl get pvc -A | awk '{print $2}' |grep   {KEYWORD} |xargs kubectl delete pvc -n
{NAME_SPACE}

11. 使用 StorageClass 提供 PV 动态存储

StorageClass 动态存储的特点是,管理员只需要创建存储服务、服务相关的 provisioner,而不用指定 PV 的大小。当用户使用存储时,只需要创建 PVC,Provisioner 会自动创建 PV 与之匹配。

  1. 在 CentOS 上搭建 NFS 服务,参考链接

  2. 安装 nfs-client-provisioner

  • helm2
1
helm install --name nfs-client --set nfs.server=x.x.x.x --set nfs.path=/data stable/nfs-client-provisioner
  • helm3
1
2
helm repo add stable https://charts.helm.sh/stable
helm install nfs-client stable/nfs-client-provisioner --set nfs.server=x.x.x.x --set nfs.path=/data

但 nfs-client-provisioner 已经停止维护,同时不支持高版本的 Kubernetes,推荐使用 csi-nfs 方案。

  1. 查看 StorageClass
1
2
3
kubectl get sc

nfs-client        cluster.local/nfs-client-nfs-client-provisioner   18s
  1. 指定 DefaultStorageClass
1
kubectl patch storageclass nfs-client -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  1. 创建一个 PVC 测试

新建文件 pvc.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 30Gi

执行命令:

1
kubectl create -f pvc.yaml

查看 PVC:

1
2
3
4
kubectl get pvc

NAME   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc1   Bound    pvc-24e4dfc1-cb8b-444b-8e3c-36ec8350df3c   30Gi       RWX            nfs-client     2m

可以看到 pvc1 状态已经是 Bound,同时在 nfs 共享目录下发现,新文件夹 default-pvc1-pvc-24e4dfc1-cb8b-444b-8e3c-36ec8350df3c 。

12. 部署 csi-nfs

  • 安装 cis-driver-nfs
1
2
helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs --namespace kube-system --version v4.9.0
  • 创建 StorageClass
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi-node1
provisioner: nfs.csi.k8s.io
parameters:
  server: x.x.x.x
  share: /data/nfs
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
  - nfsvers=4.1

有些公有云的 NFS 可能不支持 nfsvers=4.1,可以尝试去掉这个参数。

  • 创建测试 PVC
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-csi-node1-test
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 30Gi
  storageClassName: nfs-csi-node1

13. Kubernetes 集群添加新的 Node 节点

在执行 kubeadm init 时,Console 会打印添加 Node 的命令。Token 默认的有效期为 24h 。当超过有效期时,需要重新创建 Token ,执行命令:

1
2
kubeadm token create --print-join-command
kubeadm join 192.168.10.2:6443 --token ocyzce.3hv8y7w60lrvulir     --discovery-token-ca-cert-hash sha256:7a86632f54de1004bb3f38124b663f837399d6ba9aa803d58c6707a76c02a6cb

使用 Console 输出的命令,即可将 Node 节点添加到集群。

14. 控制 Node 节点的调度

  • 允许调度 Pod
1
kubectl uncordon {NODE_NAME}
  • 禁止调度 Pod
1
kubectl cordon {NODE_NAME}

15. Ingress 开启 HTTPS

准备好证书,domain.com.crt、domain.com.key

  1. 创建 Secret
1
kubectl create secret tls {SECRET_NAME} --key domain.com.key --cert domain.com.crt -n {NAMESPACE}
  1. 更新 Ingress 配置
1
2
3
4
5
spec:
  tls:
    - hosts:
        - domain.com
      secretName: { SECRET_NAME }

16. 强制删除 Kubernetes 资源

  • 使用 --force 删除
1
kubectl delete --force --grace-period=0 {RESOURCE_NAME}
  • 修改 finalizers

通常无法删除,是因为有些 finalizer 关联的动作未执行成功。如果一定要删除,可以试试下面的命令:

1
kubectl get namespace myns -o json | tr -d "\n" | sed "s/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/"| kubectl replace /api/v1/namespaces/myns/finalize -f -
  • 在 etcd 中删除
1
ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt  --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key del --prefix=/registry/namespaces/{NAMESPACENAME}

17. Kubernetes 服务仅在负载节点可用

正常情况下 NodePort 类型的 Service ,任意 Node 节点 IP + 端口,都可以访问。但是,也有可能仅负载的 Node 节点 IP + 端口可以访问。

首先,可以尝试配置转发相关参数:

1
2
3
4
5
6
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
vm.swappiness=0
EOF

另外一种可能是防火墙,没有豁免 IPENCAP 协议:

Calico 网络插件,有两种模式 BGP 、IPIP。使用 IPIP 模式时,需要在防火墙中,开启 IPENCAP 协议。

18. kubectl 获取全部使用的镜像

1
kubectl  get pod --all-namespaces -o=jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{range .spec.initContainers[*]}{.image}{"\n"}{end}{end}' | sort -u

19. 使用 Telepresence 远程调用 Kubernetes

Telepresence 是 CNCF 基金会下的一个项目。它的工作原理是在本地和 Kubernetes 集群之间,搭建一个透明的双向代理。

使用 Telepresence 可以实现的功能:

  • 本地的服务就可以完整的访问到远程集群中的其他服务。
  • 本地的服务直接访问到 Kubernetes 里的各种资源,包括环境变量、Secrets、ConfigMap 等。
  • 集群直接访问到本地暴露出来的接口。
  1. kubectl 安装配置。

在本地,安装并配置 kubectl ,使其可以正常访问 Kubernetes 集群。

  1. 安装 Telepresence
1
2
brew cask install osxfuse
brew install datawire/blackbird/telepresence
  1. 本地连通远程分支
  1. 本地访问远程集群服务

找到服务域名:

1
2
3
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.233.0.1     <none>        443/TCP    2h
myservice    ClusterIP   10.233.4.163   <none>        8000/TCP   2m

打开本地任意 Console ,即可直接访问集群内部服务:

1
curl http://myservice:8000
  1. 远程集群访问本地服务

远程集群通过端口 8000 ,访问本地 8080 端口服务,有两种方式:

  • 新建 Deployment
1
telepresence --new-deployment new_deploy_name --expose 8080:8000
  • 替换已经存在的 Deployment
1
telepresence --swap-deployment existed_deploy_name --expose 8080:8000

20. 重启 Kubernetes 中的 Job 任务

1
kubectl -n {NAMESPACE} get job {JOB_NAME} -o json | jq 'del(.spec.selector)' | jq 'del(.spec.template.metadata.labels)' | kubectl replace --force -f -

如果提示没有找到 jq 命令,需要先按照 jq ,yum install -y jq

21. macOS 快速切换不同 Kubernetes 环境

涉及 Kubernetes 相关开发时,经常需要在多个集群之间切换。配置多集群 context 是一个选择,但是如果集群在不断重置,可以试下如下方法:

~/.profile 文件中定义一系列相关 function,切换时只需要执行 on_cluster_name 即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Switch Kubernetes Cluster
function switch_kubeconfig(){
   sudo sed -i "" "/$2/d" /etc/hosts
   sudo echo "$1 $2" >> /etc/hosts

   if test -f ~/.ssh/known_hosts; then
     sed -i "" '/kubernetes.default/d'  ~/.ssh/known_hosts
   fi
   sshpass  -p "your_password" ssh -o StrictHostKeyChecking=no root@$1 "cat /etc/kubernetes/admin.conf" > ~/.kube/config
}
function on_dev1(){
   switch_kubeconfig 10.10.10.11 kubernetes.default
}

22. 给 Pod 附加容器,调试 Kubernetes 运行环境

在 Service Mesh 中,为了减少对原有系统的干扰,推荐采用 Sidecar 模式进行设计和实践。Sidecar 设计模式可以给应用程序添加新的功能,而无需额外第三方组件的配置和代码。

借助 Sidecar ,可以对运行中的容器或未运行的容器环境进行处理,解决一些运维问题。

第一步,添加 Sidecar 容器,共享存储、网络等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  Containers:
    - name: sidecar
      image: busybox:1.28.4
      command:
        - sleep
        - "3600"
      imagePullPolicy: IfNotPresent
      resources: {}
      terminationMessagePath: /dev/termination-log
      terminationMessagePolicy: File
      volumeMounts:
        - name: db-persistent-storage
          mountPath: /var/lib/mysql

第二步,进入 Sidecar 容器解决运维故障

1
kubectl exec -it {POD_NAME}  -c sidecar sh

参考,Istio Sidecar 注入:例外和除错

23. 使用 Journalctl 查看日志

Systemd 是 Linux 系统工具,用来启动守护进程。journald 收集由内核、initrd 以及服务等产生的日志信息。

只需要 journalctl 一条命令,就可以查看所有日志。

  • 查看所有日志
  • 实时滚动显示日志
  • 查看指定服务日志