最近在本机macOS安装了开发用的k8s集群之后,花了些时间研究k8s,在这个过程中有一些零零星星的实操技巧,在这里记录一下,这些实际操作技巧均是在之前搭建的单机环境验证过的,可以作为其它环境的参考。

利其器

发现两个工具可以极大提高效率,这里首先提一下。

kube-ps1

为命令行终端增加k8s相关的$PROMPT字段,安装方法如下:

brew install kube-ps1
# 然后在~/.zshrc最后添加以下两行
# source "/usr/local/opt/kube-ps1/share/kube-ps1.sh"
# PROMPT='$(kube_ps1)'$PROMPT

# 重新加载一下zshrc的配置
source ~/.zshrc

然后在执行kubectl命令里就可以明确地知道上下文及命名空间了。

image-20180520201132422

kube-shell

这个就更强大了,交互式带命令提示的kubectl终端。不过官方最新版本有问题,可以安装我这里准备好的稳定版本:

git clone https://github.com/jeremyxu2010/kube-shell.git
cd kube-shell
git checkout stable
pip install . --user -U

然后就可以敲kube-shell命令使用了,功能很强大,使用文档见这里

k8s里的基本概念

k8s里的基本概念比较多,不过设计上还是比较简单的,大概浏览下Jimmy Song写的kubernetes-handbook这些章节3.1.** Kubernetes架构3.4. Pod状态与生命周期管理3.5. 集群资源管理3.6. 控制器3.7. 服务发现3.8. 身份与权限控制3.9. 存储,就差不多了。

Ingress Controller

部署在k8s里的服务总要想办法让外部访问到,不可能每次都是用type:NodePort来解决问题,这里我用traefik-ingress-controllernginx-ingress-controller,分别解决http和tcp协议服务的外部暴露问题。

traefik-ingress-controller

安装起来参考官方文档就好了,这里简要列一下步骤:

# 创建相关服务帐户及集群角色、集群角色绑定
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-rbac.yaml

# 以DaemonSet方式部署
kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-ds.yaml

# 这里再编辑一下traefik-ingress-service,去掉nodePort, 将port修改为80, type修改为LoadBalancer
kubectl edit service traefik-ingress-service

# 最后重启一下Docker for macOS
docker ps -q | xargs -L1 docker stop
test -z "$(docker ps -q 2>/dev/null)" && osascript -e 'quit app "Docker"'
open --background -a Docker

dockerk8s都启动完成,这时会发现本机的80端口处于监听状态了,用浏览器直接访问,当然是看不到正常的页面的,因为还要提交Ingress,也比较简单:

$ cat traefik-web-ui.yml
apiVersion: v1
kind: Service
metadata:
  name: traefik-web-ui
  namespace: kube-system
spec:
  selector:
    k8s-app: traefik-ingress-lb
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-web-ui
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: traefik-ui.local
    http:
      paths:
      - backend:
          serviceName: traefik-web-ui
          servicePort: 80

# 用上述描述文件部署
$ kubectl apply -f traefik-web-ui.yml

再在/etc/hosts文件中把traefik-ui.local这个域名指向本机,然后就可以在浏览器中访问http://traefik-ui.local/了。

类似的,其它http协议的service以后type都可以只设为ClusterIP,然后配置一个Ingress通过traefik-ingress-controller暴露出去了。比如现在暴露kubernetes-dashboard就很方便了:

# 将hostPort删除, 将type修改为ClusterIP
$ kubectl edit service kubernetes-dashboard

$ cat kubernetes-dashboard.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: traefik
  name: k8s-dashboard
  namespace: kube-system
spec:
  rules:
  - host: k8s-dashboard.local
    http:
      paths:
      - backend:
          serviceName: kubernetes-dashboard
          servicePort: 443
        path: /

# 用上述描述文件部署
$ kubectl apply -f kubernetes-dashboard.yml

再在/etc/hosts文件中把k8s-dashboard.local这个域名指向本机,然后就可以在浏览器中访问http://k8s-dashboard.local/了。

这里有一个小插曲,因为本机安装的k8s-dashboard的证书不合法,为了让traefik-ingress-controller可正常反向代理到它,需要修改traefik-ingress-controller的一个参数:

# 给容器添加一个--insecureSkipVerify=true的启动参数
kubectl edit daemonset traefik-ingress-controller

nginx-ingress-controller

假设k8s集群中有一个mysql服务需要暴露给外部访问,这时就用得上nginx-ingress-controller了,安装方法也很类似:

# 部署nginx-ingress-controller相关的服务帐户、集群角色、集群角色绑定、Deployment、ConfigMap
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

# 暴露某些端口
$ cat nginx-ingress-service.yml
kind: Service
apiVersion: v1
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app: ingress-nginx
spec:
  externalTrafficPolicy: Local
  type: LoadBalancer
  selector:
    app: ingress-nginx
  ports:
  - name: mysql
    port: 3306
    targetPort: 3306

# 用上述描述文件部署
$ kubectl apply -f nginx-ingress-service.yml

# 等一会儿后,重启Docker for macOS后,应该有进程监听3306端口了
$ lsof -i :3306
COMMAND     PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
com.docke 36484 jeremy   37u  IPv4 0xe746861636421a57      0t0  TCP *:mysql (LISTEN)
com.docke 36484 jeremy   39u  IPv6 0xe7468616205d110f      0t0  TCP localhost:mysql (LISTEN)

# 然后创建tcp服务相关的ConfigMap,其中mysql是mysql服务的名称,如要反向代理其它tcp服务,相应地修改data里的定义
$ cat  nginx-tcp-configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-tcp-configmap
  namespace: kube-system
data:
  "3306": default/mysql:3306

# 最后修改nginx-ingress-controller运行时的参数,指定tcp服务反向代理的configmap,添加--tcp-services-configmap=kube-system/nginx-tcp-configmap启动参数
kubectl edit deployment nginx-ingress-controller

这时在本机就可以访问mysql服务了:

mysql -uroot -p -h127.0.0.1 -P3306

至此,无论是http协议还是tcp协议的服务,都可以很方便地暴露给外部使用了。

部署基础服务

常规的基础服务都已经用别人已经打好的包,可以通过helm来安装,helm的安装方法也比较简单:

$ brew install kubernetes-helm

# helm在k8s里初始化
$ helm init

# 查询mq相关的包
$ helm search mq
NAME                               	CHART VERSION	APP VERSION	DESCRIPTION
stable/prometheus-rabbitmq-exporter	0.1.1        	v0.28.0    	Rabbitmq metrics exporter for prometheus
stable/rabbitmq                    	1.1.2        	3.7.5      	Open source message broker software that implem...
stable/rabbitmq-ha                 	1.5.0        	3.7.4      	Highly available RabbitMQ cluster, the open sou...

# 这样就会将别人打好的rabbitmq包部署起来
$ helm install stable/rabbitmq -n testmq

安装的时候还可以指定定制的参数,参见这里

使用命令helm search可以看到目前仓库里别人打好的helm chart,发现redis, mysql, rabbitmq等常用基础组件都有了,真的是很方便。即使有一些组件比较特殊没有,也可以参考kubernets/chartsDeveloping Templates模仿写一个chart。

参考

  1. https://forums.docker.com/t/restart-docker-from-command-line/9420
  2. https://jimmysong.io/kubernetes-handbook
  3. https://docs.traefik.io/user-guide/kubernetes
  4. https://github.com/cloudnativelabs/kube-shell
  5. https://kubernetes.github.io/ingress-nginx
  6. https://docs.helm.sh