使用 kubeadm 安装k8s

安装版本

Kubernetes – 1.11.1

机器规划

未分类

注:三台机器已做key认证并添加hosts, 方便传送文件

系统配置(三台机器都执行)

关闭selinux及firewalld

sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
systemctl stop firewalld && systemctl disable firewalld

内核参数调整

cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

关闭swap, 注释fstab中的swap配置

swapoff -a

注: k8s 版本1.8开始要求关闭系统的swap,否则启动不了kubelet;

安装docker并启动(三台机器都执行)

docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE; 比如: 18.06 为18年6月份发布的版本;

安装包官方地址:

https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

下载安装 docker-ce 17.03版本:

wget -c https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-17.03.2.ce-1.el7.centos.x86_64.rpm
wget -c https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm
yum install -y docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm docker-ce-17.03.2.ce-1.el7.centos.x86_64.rpm

注:本次安装的版本为 17.03 ; k8s-1.11.1 对应的最高版本docker是 17.03 ;

修改docker启动配置文件:

/usr/lib/systemd/system/docker.service

# 指定监听端口、数据存储目录以及加速镜像源
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H 127.0.0.1:8888 -g /data/docker --registry-mirror=http://xxxx.io --exec-opt native.cgroupdriver=systemd

启动 docker :

systemctl daemon-reload && systemctl enable docker && systemctl start docker

导入必要的镜像

默认使用 kubeadm 初始化集群时需要从 k8s.gcr.io 地址上拉取相关镜像,如果可以科学上网的,这一步可以省略;

master节点执行:

images=(kube-apiserver-amd64.tar kube-controller-manager-amd64.tar kube-scheduler-amd64.tar kubernetes-dashboard-amd64.tar etcd-amd64.tar coredns.tar flannel.tar kube-proxy-amd64.tar pause.tar)
for i in ${images[@]};do
    docker load < $(dirname $script_dir)/$i
done

node节点执行:

images=(flannel.tar kube-proxy-amd64.tar pause.tar)
for i in ${images[@]};do
    docker load < $(dirname $script_dir)/$i
done

镜像分享地址:

链接: https://pan.baidu.com/s/1jtT0qHpcz1WjovIBP6JOwQ 密码:5xxn

安装 kubeadm (三台机器都执行)

添加 yum 源:

cat > /etc/yum.repos.d/kubernetes.repo <<EOF 
[kubernetes] 
name=Kubernetes 
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 
enabled=1 
gpgcheck=0 
repo_gpgcheck=0 
EOF

安装 kubeadm :

# 列出最新版本
yum list kubeadm --showduplicates
# 安装
yum install kubeadm-1.11.1

注:安装 kubeadm ,相关依赖会安装 kubectl、kubelet、kubernetes-cni ; kubectl 是管理集群的工具,kubelet 是每个node节点都会运行的一个服务,用于管理节点的docker启动、网络组件等功能;

配置启动 kubelet (三台机器都执行)

确保kubelet和docker使用同一个cgroupdriver, 这里使用systemd;

kubelet 额外参数配置:

/etc/sysconfig/kubelet

KUBELET_EXTRA_ARGS="--runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice"

启动 kubelet :

systemctl enable kubelet && systemctl start kubelet

初始化k8s集群 (master机器执行)

初始化:

kubeadm init --apiserver-advertise-address 10.211.55.10 --pod-network-cidr=10.10.0.0/16  --kubernetes-version=v1.11.1

初始化完成后会有以下提示:

[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join 10.211.55.10:6443 --token 4zfhdz.8jue59q95hzoc7p9 --discovery-token-ca-cert-hash sha256:da756adb30db06963db480d3868b9acd02c2e38271314baf62e9d28c6629ae92

增加kubectl权限访问:

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

配置 k8s 网络 – flannel

Kubernetes支持Flannel、Calico、Weave network等多种cni网络Drivers;

配置 flannel :

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f  kube-flannel.yml

如果有多张网卡,需要在kube-flannel.yml中使用–iface参数指定集群主机内网网卡的名称, 类似 :

args:
- --ip-masq
- --kube-subnet-mgr
- --iface=eth1

查看 k8s 集群状态

查看集群状态 :

kubectl get cs

查看 pods :

kubectl get pod --all-namespaces

其它节点添加到集群

集群初始化完成后可以看到,最后有提示加入集群的命令,但token是有时间限制的,可能过一段时间就过期了,可以通过以下命令成生新的命令:

kubeadm token create --print-join-command

输出类似:

kubeadm join 10.211.55.10:6443 --token pxlvg5.puu7a0mrhpoif16e --discovery-token-ca-cert-hash sha256:f732ceef958151c56583641048ce6a11c39f960166969fb8f782374c3b4a7570

查看已有 token :

kubeadm token list

部署 k8s Dashboard

下载部署配置文件:

wget https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml

指向端口类型为 NodePort , 可以使用 节点ip:端口 访问 :

修改 kubernetes-dashboard.yaml

# ------------------- Dashboard Service ------------------- #

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
  selector:
    k8s-app: kubernetes-dashboard

因 k8s 在1.6版本以后 kube-apiserver 启用了 RBAC 授权, 因此需要认证权限配置文件 :

增加 kubernetes-dashboard-admin.rbac.yaml

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-admin
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard-admin
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard-admin
  namespace: kube-system

节点增加标签用法:

kubectl label nodes <node-name> <label-key>=<label-value>
kubectl get nodes
kubectl label nodes k8s-master1 k8s-app=kubernetes-dashboard

查看 dashboard 分配到的 NodePort :

kubectl get svc,pod --all-namespaces | grep dashboard

创建 dashboard 的 pod :

kubectl create -f kubernetes-dashboard.yaml
kubectl create -f kubernetes-dashboard-admin.rbac.yaml

查看登陆 dashboard 的token :

kubectl -n kube-system describe $(kubectl -n kube-system get secret -n kube-system -o name | grep namespace) | grep token

kubectl 命令补全

yum install -y bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

K8S之traefik

Traefik

Traefik是一个用Golang开发的轻量级的Http反向代理和负载均衡器。由于可以自动配置和刷新backend节点,目前可以被绝大部分容器平台支持,例如Kubernetes,Swarm,Rancher等。由于traefik会实时与Kubernetes API交互,所以对于Service的节点变化,traefik的反应会更加迅速。总体来说traefik可以在Kubernetes中完美的运行.

Traefik 还有很多特性如下:

  • 速度快
  • 不需要安装其他依赖,使用 GO 语言编译可执行文件
  • 支持最小化官方 Docker 镜像
  • 支持多种后台,如 Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS 等等
  • 支持 REST API
  • 配置文件热重载,不需要重启进程
  • 支持自动熔断功能
  • 支持轮训、负载均衡
  • 提供简洁的 UI 界面
  • 支持 Websocket, HTTP/2, GRPC
  • 自动更新 HTTPS 证书
  • 支持高可用集群模式

接下来我们使用 Traefik 来替代 Nginx + Ingress Controller 来实现反向代
理和服务暴漏。

那么二者有什么区别呢?简单点说吧,在 Kubernetes 中使用 nginx 作为前端负载均衡,通过 Ingress Controller 不断的跟 Kubernetes API 交互,实时获取后端 Service、Pod 等的变化,然后动态更新 Nginx 配置,并刷新使配置生效,来达到服务自动发现的目的,而 Traefik 本身设计的就能够实时跟 Kubernetes API 交互,感知后端 Service、Pod 等的变化,自动更新配置并热重载。大体上差不多,但是 Traefik 更快速更方便,同时支持更多的特性,使反向代理、负载均衡更直接更高效。

1.Role Based Access Control configuration (Kubernetes 1.6+ only)

kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-rbac.yaml

授权,官方文档不懂下下来看文档

2.Deploy Træfik using a Deployment or DaemonSet

To deploy Træfik to your cluster start by submitting one of the YAML files to the cluster with kubectl:

kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-deployment.yaml   此模板有些问题,我先用ds模板

kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-ds.yaml

deployment和ds的区别:ds会在每台node上都创造一个pod.而deploy是人为控制的副本。如果几台很多了,没有必要用ds,比如100台 会造100个pod,没有意义。自己用ds模板改下,kind: Deployment

如下

直接找到DS模板吧kind改成deploy模式
kind: Deployment

3.Check the Pods

# kubectl --namespace=kube-system get pods -o wide 
traefik-ingress-controller-79877bbc66-p29jh 1/1 Running 0 32m   10.249.243.182    k8snode2-175v136​

查找一下在那台服务器上,deploy会随机分配一台服务器

4.Ingress and UI

kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/ui.yaml.

自己再造个web测试用

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  template:
    metadata:
      labels:
        name: nginx-svc
        namespace: default
spec:
  selector:
    run: ngx-pod
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: ngx-pod
spec:
  replicas: 4
  template:
    metadata:
      labels:
        run: ngx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.10
        ports:
        - containerPort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ngx-ing
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: www.ha.com
    http:
      paths:
      - backend:
          serviceName: nginx-svc
          servicePort: 80

5.测试成功

未分类

6.HTTPS证书

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-web-ui
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: traefik-ui.minikube
    http:
      paths:
      - backend:
          serviceName: traefik-web-ui
          servicePort: 80
  tls:
   - secretName: traefik-ui-tls-cert

官方是怎么导入证书的呢? 注:key和crt必须要有

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=traefik-ui.minikube"
kubectl -n kube-system create secret tls traefik-ui-tls-cert --key=tls.key --cert=tls.crt

7.Basic Authentication

A. Use htpasswd to create a file containing the username and the MD5-encoded password:
htpasswd -c ./auth myusername
You will be prompted for a password which you will have to enter twice. htpasswd will create a file with the following:
cat auth
myusername:$apr1$78Jyn/1K$ERHKVRPPlzAX8eBtLuvRZ0
B. Now use kubectl to create a secret in the monitoring namespace using the file created by htpasswd
kubectl create secret generic mysecret --from-file auth --namespace=monitoring
Note
Secret must be in same namespace as the Ingress object.
C. Attach the following annotations to the Ingress object:
    ingress.kubernetes.io/auth-type: "basic"
    ingress.kubernetes.io/auth-secret: "mysecret"
They specify basic authentication and reference the Secret mysecret containing the credentials.
Following is a full Ingress example based on Prometheus:
#配置文件如下
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: prometheus-dashboard
 namespace: monitoring
 annotations:
   kubernetes.io/ingress.class: traefik
   ingress.kubernetes.io/auth-type: "basic"
   ingress.kubernetes.io/auth-secret: "mysecret"
spec:
 rules:
 - host: dashboard.prometheus.example.com
   http:
     paths:
     - backend:
         serviceName: prometheus
         servicePort: 9090

模板1 多域名暴漏端口:再看一下 UI 页面,立马更新过来,可以看到刚刚配置的 dashboard.k8s.traefik 和 ela.k8s.traefik

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dashboard-ela-k8s-traefik
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: dashboard.k8s.traefik
    http:
      paths:
      - path: /  
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
  - host: ela.k8s.traefik
    http:
      paths:
      - path: /  
        backend:
          serviceName: elasticsearch-logging
          servicePort: 9200

模板2

注意:这里我们根据路径来转发,需要指明 rule 为 PathPrefixStrip,配置为 traefik.frontend.rule.type: PathPrefixStrip

再看一下 UI 页面,也是立马更新过来,可以看到刚刚配置的 my.k8s.traefik/dashboard 和 my.k8s.traefik/kibana

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-k8s-traefik
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.frontend.rule.type: PathPrefixStrip
spec:
  rules:
  - host: my.k8s.traefik
    http:
      paths:
      - path: /dashboard
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
      - path: /kibana
        backend:
          serviceName: kibana-logging
          servicePort: 5601

8.自动熔断

在集群中,当某一个服务大量出现请求错误,或者请求响应时间过久,或者返回500+错误状态码时,我们希望可以主动剔除该服务,也就是不在将请求转发到该服务上,而这一个过程是自动完成,不需要人工执行。Traefik 通过配置很容易就能帮我们实现,Traefik 可以通过定义策略来主动熔断服务。

  • NetworkErrorRatio() > 0.5:监测服务错误率达到50%时,熔断。
  • LatencyAtQuantileMS(50.0) > 50:监测延时大于50ms时,熔断。
  • ResponseCodeRatio(500, 600, 0, 600) > 0.5:监测返回状态码为[500-600]在[0-600]区间占比超过50%时,熔断。

案例

apiVersion: v1
kind: Service
metadata:
  name: wensleydale
  annotations:
    traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" 

9.官方文档:

其他多看官方文档

https://docs.traefik.io/user-guide/kubernetes/

10.update

由于业务需求,node会扩充, ds模式多了会浪费资源 20台node+,我们怎么把traefik固定在几台机器上。查了一些文档找到了这个解决方法。

给node打标签,用ds模式启动标签化节点 :https://www.kubernetes.org.cn/daemonset 参考文档。

案例:

给三台node打标签

kubectl label nodes k8snode1-174v136-taiji traefik=svc
kubectl label nodes k8snode2-175v136-taiji traefik=svc
kubectl label nodes k8snode3-176v136-taiji traefik=svc​
查看标签
[root@k8s-m1 Traefik]# kubectl get nodes --show-labels
NAME                     STATUS    ROLES     AGE       VERSION   LABELS
k8snode1-174v136-taiji   Ready     node      42d       v1.10.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8snode1-174v136-taiji,node-role.kubernetes.io/node=,traefik=svc
[root@k8s-m1 Traefik]# cat traefik-ds.yaml 
kind: DaemonSet
apiVersion: extensions/v1beta1
metadata:
  name: traefik-ingress-controller
  namespace: kube-system
  labels:
    k8s-app: traefik-ingress-lb
spec:
  template:
    metadata:
      labels:
        k8s-app: traefik-ingress-lb
        name: traefik-ingress-lb
    spec:
      nodeSelector:
        traefik: "svc"            #重点2行
...................
验证
[root@k8s-m1 Traefik]# kubectl get ds -n kube-system 
NAME                         DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR  
traefik-ingress-controller   3         3         3         3            3           traefik=svc

总结:后期可以根据业务量加标签扩展traefik节点

k8s与数据分析–利用redash做自助数据分析

前言

在之前文章中,一直讲prometheus的metrics以及apm的指标的重要性,多侧重于收据的收集和存储。如果不对这些数据进行数据分析,那么就没有收集的意义了。通过数据分析和挖掘,让数据产生价值。一直以来我认为devops必须是一个闭环,即apm,日志,监控着三大系统的数据,必须经过分析对dev和ops有价值。
数据可视化是大数据的『最后一公里』,做好可视化是对于数据分析是重要的。
今天,主要介绍redash这款数据分析的利器。

redash简介

redash是一款开源的BI工具,提供了基于web的数据库查询和数据可视化功能。

未分类

支持 SQL, NoSQL, Big Data and API data等20几种常见的数据源:

未分类

基本上满足了大多数的场景。相比
superset,除了上手简单,支持influxdb等时序数据库。这点对于监控数据分析很有优势。

sql友好的SQL editor,更加高效的编写复杂的sql

未分类

随时写,随时查,实时看到查询的效果

  • 支持丰富的可视化展示形式
    • Boxplot
    • Chart – Line, Bar, Area, Pie, Scatter
    • Cohort
    • Counter
    • Funnel
    • Map
    • Pivot Table
    • Sankey
    • Sunburst
    • Word Cloud

未分类

角色权限相关,支持ldap等,方便与企业内部的用户体系打通。

安装和简单使用

安装

如果是想直接体验的话,docker-compose部署最简单,redashgithub仓库中直接提供了docker-compose.production.yml文件,直接docker-compose up -d 即可。

# This is an example configuration for Docker Compose. Make sure to atleast update
# the cookie secret & postgres database password.
#
# Some other recommendations:
# 1. To persist Postgres data, assign it a volume host location.
# 2. Split the worker service to adhoc workers and scheduled queries workers.
version: '2'
services:
  server:
    image: redash/redash:latest
    command: server
    depends_on:
      - postgres
      - redis
    ports:
      - "5000:5000"
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      REDASH_COOKIE_SECRET: veryverysecret
      REDASH_WEB_WORKERS: 4
    restart: always
  worker:
    image: redash/redash:latest
    command: scheduler
    environment:
      PYTHONUNBUFFERED: 0
      REDASH_LOG_LEVEL: "INFO"
      REDASH_REDIS_URL: "redis://redis:6379/0"
      REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
      QUEUES: "queries,scheduled_queries,celery"
      WORKERS_COUNT: 2
    restart: always
  redis:
    image: redis:3.0-alpine
    restart: always
  postgres:
    image: postgres:9.5.6-alpine
    # volumes:
    #   - /opt/postgres-data:/var/lib/postgresql/data
    restart: always
  nginx:
    image: redash/nginx:latest
    ports:
      - "80:80"
    depends_on:
      - server
    links:
      - server:redash
    restart: always

通过compose文件可以看出,redash依赖redis和pgsql数据库。redis用来缓存一些查询result,而pgsql是元数据库,目前不支持mysql替换pgsql。

其他安装方式,见官方文档https://redash.io/help/open-source/setup

简单使用

先上一张实际的效果图:

未分类

包含了couter和area chart。
数据源包括influxdb时序数据库,和mysql业务库。

未分类

其中audit-middware 其实是Query Results库。Query Results Data Source 允许你在一些已经存在的查询结果之上再做一些高级的查询, 这样就可以轻易合并一些查询结果。

总结

在实际使用中,redash和superset各有优劣。根据自己的场景来选择吧。查阅资料的过程中,已经有人对redash做了二次开发,这也许是深度使用的必经之路。
为什么非要使用这种开源BI可视化工具?
因为如果是前后端配合的话,工作量会很大。而且也很难实现随时修改随时上线。不过这取决于前期数据的完整性。

面向业务开发者的 k8s 基本命令

随着容器技术的发展,k8s 也越来越火热。在网络上有许多关于 k8s 的文章,但大部分都是关于集群部署相关的,

而这篇文章主要讲作为应用开发者如何使用 k8s 。

github: https://github.com/shfshanyue/blog/tree/master/Articles/Kubenetes-Commands

准备

预备知识

Docker,学习 k8s 之前了解 Docker 是毋庸置疑的。

工具

brew install kubectl

kubectl 是 k8s 的命令行工具,用于管理 k8s 集群。以上是 Mac 下的安装方法,其它操作系统参考官方文档。当然,你也可以使用 Dashboard 管理容器。

Cluster

k8s 集群,一般生产环境有一个 Cluster 集群,测试环境有一个 Cluster 集群。

Namespace

在一个 Cluster 会有不同的 Namespace,可以区分不同的业务团队。

Pod

Pod 是 k8s 中最小的可部署单元。一般一个 Pod 运行一个 Container,但是有时也会运行多个 Container。类似 docker-compose。

Deployment

Deployment 用来控制 Pod,比如控制一个应用起几个 Pod。

配置文件

关于 k8s 的配置文件位置在 ~/.kube/config。另外也可以使用命令 kubectl config 查看以及更改配置,使用命令更改配置的同时,配置文件也会改变。

配置文件可以指定 Cluster,Namespace,User 的配置,并设置 Context。以下是一个简版的配置文件。

# 该配置文件配置了一个用户 shanyue,一个集群 dev,并且设置了 dev 的 context
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /Users/shanyue/.minikube/ca.crt
    server: https://192.168.99.100:8443
  name: dev
contexts:
- context:
    cluster: dev
    namespace: Business
    user: shanyue
  name: dev
current-context: dev
kind: Config
preferences: {}
users:
- name: shanyue
  user:
    client-certificate: /Users/shanyue/.minikube/client.crt
    client-key: /Users/shanyue/.minikube/client.key

其中 current-context 代表当前上下文,也可以通过以下命令来设置上下文。

# 查看配置
kubectl config view

# 查看集群列表
kubectl config get-clusters

# 查看 Context 列表
kubectl config get-contexts

# 设置当前 Context
kubectl config use-context dev

创建资源

kubectl create 代表根据文件创建资源,可以是 Deployment,也可以是 Pod。

kubectl run 代表根据镜像创建资源。

kubectl create -f app.yaml

kubectl run --image=k8s.gcr.io/echoserver:1.10 --port=8080

一般在 CI 中作 deploy 时会使用 kubectl apply 命令,根据配置文件更新资源。

配置文件中可以写多份配置,也可以写 Deployment,Service 各种 Kind 配置。以下是以 node 作为服务器语言样例的配置。

apiVersion: v1
kind: Service
metadata:
  name: app
  namespace: dev
  labels:
    name: app
spec:
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP
  selector:
    name: app

---

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app
  namespace: dev
  labels:
    name: app
spec:
  template:
    metadata:
      labels:
        name: app
    spec:
      containers:
      - name: app
        image: node
        imagePullPolicy: Always
        env:
        - name: PORT
          value: "8080"
        ports:
        - containerPort: 8080

访问资源

以下 $app 代表特定 Pod 的 Name

# 获取当前 Context 下所有的 Deployment
kubectl get deployments

# 获取当前 Context 下所有的 Pod
kubectl get pods

# 获取当前 Cluster 下所有的 Pod
kubectl get pods --all-namespaces

# 获取特定 Pod 的状态
kubectl describe pod $app

# 进入某个 Pod 容器里边的命令行
kubectl exec -it $app bash

# 查看某个 Pod 的日志
kubectl logs $app

ansible安装k8s步骤及注意事项(在线安装)

以下步骤都经本人实测,可以完美运行。

官方参考网址:https://github.com/gjmzj/kubeasz/

Ansible了解

ansible是个什么东西呢?官方的title是“Ansibleis Simple IT Automation”——简单的自动化IT工具。这个工具的目标有这么几项:

自动化部署APP;

自动化管理配置项;

自动化的持续交互;

自动化的(AWS)云服务管理;

所有的这几个目标从本质上来说都是在一个台或者几台服务器上,执行一系列的命令而已。通俗的说就是批量的在远程服务器上执行命令。当然,最主要的是它是基于 paramiko 开发的。这个paramiko是什么呢?它是一个纯Python实现的ssh协议库。因此fabric和ansible还有一个共同点就是不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的。

未分类

由上面的图可以看到 Ansible 的组成由 5 个部分组成:

  • Ansible : 核心

  • Modules : 包括 Ansible 自带的核心模块及自定义模块

  • Plugins : 完成模块功能的补充,包括连接插件、邮件插件等

  • Playbooks : 剧本;定义 Ansible 多任务配置文件,由Ansible 自动执行

  • Inventory : 定义 Ansible 管理主机的清单

具体的命令可以查看参考(中文权威指南):http://www.ansible.com.cn/docs/intro_installation.html

安装k8s

1. 安装依赖工具

# 文档中脚本默认均以root用户执行# 安装 epel 源并更新
yum install epel-release –y(最好每台机器装一下)
yum install net-tools
yum update# 删除不要的默认安装
yum erase firewalld firewalld-filesystem python-firewall -y# 安装python
yum install python -y

2. 安装ansible

# CentOS 7
yum install git python-pip -y# pip安装ansible(国内如果安装太慢可以直接用pip阿里云加速)#pip install pip --upgrade#pip install ansible
pip install pip --upgrade -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
pip install --no-cache-dir ansible -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

3. 在deploy节点配置免密码登陆

ssh-keygen -t rsa -b 2048 回车 回车 回车
ssh-copy-id $IPs #$IPs为所有节点地址包括自身,按照提示输入yes 和root密码
(即使是本机也需要配置)

4. 在deploy节点编排k8s安装

# 下载项目文件
git clone https://github.com/gjmzj/kubeasz.git
mv kubeasz /etc/ansible# 下载已打包好的binaries,并且解压缩到/etc/ansible/bin目录# 国内请从我分享的百度云链接下载 https://pan.baidu.com/s/1c4RFaA # 如果你有合适网络环境也可以按照/down/download.sh自行从官网下载各种tar包到 ./down目录,并执行download.sh
tar zxvf k8s.191.tar.gz
mv bin/* /etc/ansible/bin
cd /etc/ansible
cp example/hosts.m-masters.example hosts# 根据上文实际规划修改此hosts文件
vi hosts

验证ansible安装

在deploy 节点使用如下命令

ansible all -m ping

如果配置正确可以看到类似输出:

192.168.1.42 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "ping": "pong"
}
192.168.1.43 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "ping": "pong"
}
192.168.1.44 | SUCCESS => {
    "changed": false, 
    "failed": false, 
    "ping": "pong"
}

5. 安装集群

注意:

1)如何重复安装时,注意在执行完卸载命令后,将/etc/kubernetes目录删除

2)安装02.etcd时往往不能够一次性成功安装,如何执行过程中有错误应执行第二遍02.etcd.yml(不管使用90.setup.yml或是02.etcd.yml安装)

#ansible-playbook 01.prepare.yml
#ansible-playbook 02.etcd.yml
#ansible-playbook 03.kubectl.yml
#ansible-playbook 04.docker.yml
#ansible-playbook 05.kube-master.yml
#ansible-playbook 06.kube-node.yml
#ansible-playbook 07.calico.yml 或者 ansible-playbook 07.flannel.yml 只能选择一种网络插件
#ansible-playbook 90.setup.yml # 一步安装
#ansible-playbook 99.clean.yml # 一步安装

source /etc/profile(环境变量设置未生效,kubectl工具不能使用)

自动安装时没有环境变量,需要source一下;

单主单节点

发现问题:ansible1.8在重新安装并没有完全删除掉/etc/kubernetes中的东西,1.9没啥问题,所以1.8需要将/etc/kubernetes中的东西全部删掉再运行;否则在安装06node时csr验证会报错。

还有装02.etcd时配置文件读不到的问题,运行两次就好了;

ansible 1.9没有问题

安装DNS/dashboard时,注意dashboard-controller.yaml中deployment的版本为extensions/v1beta1

规律,可以先执行90.setup,然后执行2.etcd

卸载的时候注意删除掉/etc/kubernetes目录

注意:api-server是以https(用户名密码启动的),所以最后需要为用户配置角色才可以通过url进行访问:

绑定api-server的权限(否则是注册不上的)

kubectlcreate clusterrolebinding kubelet-node-clusterbinding1 --clusterrole=cluster-admin--user=admin

k8s的初步部署zipkin和elk

kubernates的部署

一、界面部署

1、创建

点击右上角创建按钮

未分类

2、设置创建的参数

选择创建的方式可以为输入yaml配置,上传yaml文件和界面配置。

①界面创建

未分类

应用名称

这个是部署pod的名称
- 容器镜像
输入要部署的容器的镜像地址
- 容器组个数
这个参数是k8s要保证运行的pod数量,如果指定3,它会创建3个Pod,并且持续监控它们。如果某个Pod不响应,那么Replication Controller会替换它,保持总数为3。如果之前不响应的Pod恢复了,现在就有4个Pod了,那么Replication Controller会将其中一个终止保持总数为3。
- 服务
选择内部或者外部,内部服务将使得集群外部请求不能访问到pod,外部则会暴露nodePort使得外部机器可访问,服务中的端口类型共有3种:

1)nodePort
 外部机器可访问的端口。
比如一个Web应用需要被其他用户访问,那么需要配置type=NodePort,而且配置nodePort=30001,那么其他机器就可以通过浏览器访问scheme://node:30001访问到该服务,例如http://node:30001。
 例如MySQL数据库可能不需要被外界访问,只需被内部服务访问,那么不必设置NodePort
2)targetPort
 容器的端口(最根本的端口入口),与制作容器时暴露的端口一致(DockerFile中EXPOSE),例如docker.io官方的nginx暴露的是80端口。
3)port
 kubernetes中的服务之间访问的端口,尽管mysql容器暴露了3306端口(参考https://github.com/docker-library/mysql/的DockerFile),但是集群内其他容器需要通过33306端口访问该服务,外部机器不能访问mysql服务,因为他没有配置NodePort类型

- 保密字典
当要拉取私有服务器的镜像的时候需要用户名密码,在k8s中这个是通过配置保密字典secret来实现的。
K8s 中Secret是一个包含少量敏感信息如密码,令牌,或秘钥的对象。这些信息可能被保存在 pod 定义或者 docker 镜像中,把这些信息保存在 Secret对象中,可以在这些信息被使用时加以控制,并可以降低信息泄露的风险。
创建保密字典的方式有很多种,我是通过命令行的方式配置的:

kubectl create secret docker-registry regsecret --docker-server=repo.gildata.com --docker-username=chenyang --docker-password=xxxx [email protected]

这行命令是创建了一个名为regsecret的保密字典,--docker-server表示为仓库地址,--docker-username是用户账户,--docker-password为账户密码,--docker-email用户邮箱。

这个配置完之后,在k8s的界面上就可以看到我们配置的保密字典:

未分类

在界面上选择的时候可以点击下面的高级按钮选择相应的保密字典:

未分类

选择刚刚创建的保密字典:

未分类

这样私有仓库的镜像就可以拉取了。

②yaml配置
1)zipkin的Deployment配置:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: zipkin
spec:
  replicas: 1
  template:
    metadata:
      labels:
        k8s-app: zipkin
    spec:
      containers:
      - name: zipkin
        image: openzipkin/zipkin
        ports:
          - containerPort: 9411
            hostPort: 9411

我在这里直接用Deployment来管理pod,Deployment为Pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。典型的应用场景包括:

  • 定义Deployment来创建Pod和ReplicaSet
  • 滚动升级和回滚应用
  • 扩容和缩容
  • 暂停和继续Deployment

把这段配置文件提交在k8s管理界面的yaml文件框里面,或者直接是提交本地yaml文件,这两种方法大同小异。

附:k8s的pod的配置所有选项介绍:

 # yaml格式的pod定义文件完整内容:
 apiVersion: v1          #必选,版本号,例如v1
 kind: Pod             #必选,Pod
 metadata:             #必选,元数据
   name: string          #必选,Pod名称
   namespace: string       #必选,Pod所属的命名空间
   labels:             #自定义标签
     - name: string       #自定义标签名字
   annotations:          #自定义注释列表
     - name: string
 spec:                #必选,Pod中容器的详细定义
   containers:           #必选,Pod中容器列表
   - name: string        #必选,容器名称
     image: string       #必选,容器的镜像名称
     imagePullPolicy: [Always | Never | IfNotPresent]  #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
     command: [string]       #容器的启动命令列表,如不指定,使用打包时使用的启动命令
     args: [string]         #容器的启动命令参数列表
     workingDir: string      #容器的工作目录
     volumeMounts:         #挂载到容器内部的存储卷配置
     - name: string         #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
       mountPath: string     #存储卷在容器内mount的绝对路径,应少于512字符
       readOnly: boolean     #是否为只读模式
     ports:              #需要暴露的端口库号列表
     - name: string         #端口号名称
       containerPort: int    #容器需要监听的端口号
       hostPort: int        #容器所在主机需要监听的端口号,默认与Container相同
       protocol: string      #端口协议,支持TCP和UDP,默认TCP
     env:              #容器运行前需设置的环境变量列表
     - name: string        #环境变量名称
       value: string       #环境变量的值
     resources:          #资源限制和请求的设置
       limits:           #资源限制的设置
         cpu: string       #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
         memory: string      #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
       requests:         #资源请求的设置
         cpu: string       #Cpu请求,容器启动的初始可用数量
         memory: string      #内存清楚,容器启动的初始可用数量
     livenessProbe:        #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
       exec:             #对Pod容器内检查方式设置为exec方式
         command: [string]   #exec方式需要制定的命令或脚本
       httpGet:            #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
         path: string
         port: number
         host: string
         scheme: string
         HttpHeaders:
         - name: string
           value: string
       tcpSocket:            #对Pod内个容器健康检查方式设置为tcpSocket方式
          port: number
        initialDelaySeconds: 0   #容器启动完成后首次探测的时间,单位为秒
        timeoutSeconds: 0      #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
        periodSeconds: 0       #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
        successThreshold: 0
        failureThreshold: 0
        securityContext:
          privileged: false
     restartPolicy: [Always | Never | OnFailure] #Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
     nodeSelector: obeject     #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
     imagePullSecrets:         #Pull镜像时使用的secret名称,以key:secretkey格式指定
     - name: string
     hostNetwork: false        #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
     volumes:              #在该pod上定义共享存储卷列表
     - name: string          #共享存储卷名称 (volumes类型有很多种)
       emptyDir: {}          #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
       hostPath: string        #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
         path: string        #Pod所在宿主机的目录,将被用于同期中mount的目录
       secret:             #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
         scretname: string  
         items:     
         - key: string
           path: string
       configMap:          #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
         name: string
         items:
         - key: string
           path: string    

2)service配置

在pod成功部署之后,就需要为这个pod配置service。

Kubernete Service 是一个定义了一组Pod的策略的抽象,我们也有时候叫做宏观服务。这些被服务标记的Pod都是(一般)通过label Selector决定的。

举个例子,我们假设后台是一个图形处理的后台,并且由3个副本。这些副本是可以相互替代的,并且前台并不需要关心使用的哪一个后台Pod,当这个承载前台请求的pod发生变化时,前台并不需要直到这些变化,或者追踪后台的这些副本,这些都是通过服务来定位追踪的。

简单地说,服务就是请求到pod的一座桥梁,请求并不需要关心自己会请求到哪个pod,这些对于用户和请求来说都是不可见的,用户也不会感觉到这是一个集群,一个请求过来,service会自动分配到哪个pod上。

service的yaml配置文件:

apiVersion: v1
kind: Service
metadata:
 name: zipkin
 labels:
   k8s-app: zipkin
spec:
 type: LoadBalancer
 ports:
 - port: 9411
   targetPort: 9411
   nodePort: 30002
 selector:
  k8s-app: zipkin

2)ConfigMap配置

ConfigMap用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件。ConfigMap跟secret很类似,但它可以更方便地处理不包含敏感信息的字符串。

简单的说,相对于docker-compose的配置文件在文件目录下面,k8s的配置文件放到了自己的配置字典里面。

下面是ConfigMap的配置

apiVersion: v1
kind: ConfigMap
metadata:
  name: logstash-config
  namespace: default
data:
  logstash.yml: |
    http.host: "0.0.0.0"
    path.config: /usr/share/logstash/pipeline
  logstash.conf: |
    input {
        tcp {
            port => 5000
            codec => json_lines {
                charset => "UTF-8"
            }
        }
    }
    output {
        elasticsearch {
            hosts => "elasticsearch:9200"
        }
    }

logstash-config表示配置字典的名称。

data里面每一个key-value键值对都会生成一个文件,key为文件名,value为内容。

同样的,在点击上传之后,会在配置字典菜单中生成相应的配置字典。如图所示:

未分类

这样就可以在deployment中引用这个配置字典:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: logstash
spec:
  replicas: 1
  template:
    metadata:
      labels:
        k8s-app: logstash
    spec:
      containers:
      - name: logstash
        image: docker.elastic.co/logstash/logstash:6.2.3
        ports:
          - containerPort: 5000
            hostPort: 5000
        env:
          - name: ES_JAVA_OPTS
            value: "-Xmx256m -Xms256m"
        volumeMounts:
          - name: logstash-volume1   #volumes中配的volume名字
            mountPath: /usr/share/elasticsearch/config   #在容器内部的配置文件存放地址
          - name: logstash-volume2   #volumes中配的volume名字
            mountPath: /usr/share/logstash/pipeline     #在容器内部的配置文件存放地址
        imagePullSecrets:
          - name: regsecret   #  保密字典
      volumes:
      - name: logstash-volume1  #这个是现在自定义的volume的名字,方便在volumeMounts中引用
        configMap:
          name: logstash-config   #这个就是之前配的配置字典
          items:
          - key: logstash.yml  #配置字典里面对应的key
            path: config
      - name: logstash-volume2   #这个是现在自定义的volume的名字,方便在volumeMounts中引用
        configMap:
          name: logstash-config   #这个就是之前配的配置字典
          items:
          - key: logstash.conf   #配置字典里面对应的ke
            path: pipeline

3、部署

配置好之后点击部署,然后查看概况,状态图都为绿色,容器组的状态为running,这样就部署成功了,如图:

未分类

可以进行访问Zipkin,输入http://10.106.0.51:32552,这里的32552即为nodePort:

未分类

当在后期需要调整node的数量的时候,可以在deployment中调整数量,如图所示:

未分类

第二步:

未分类

K8S Ingress环境下,Http Redirect端口丢失问题

近日发现一个问题:应用程序在返回Http Redirect的时候丢失了原先访问的端口。比如,我们这样访问http://IP-A:Port-A/app/delete,这个url会响应302,但是它返回的Response header Location里丢失了端口,正确的结果应该是这样:http://IP-A:Port-A/app/index,但返回的却是:http://IP-A/app/index,把端口丢失了。

基本情况

我们的部署情况是这样的:

  • 部署了Nginx Ingress,并使用NodePort的方式把Nginx Ingress Service暴露出来
  • 配置了App的Ingress

服务器信息:

未分类

其实以上也不全是服务器,其中有两个K8S Service不是服务器,它们是VIP,关于这个请看K8S – Using Source IP一文,当访问http://IP-A:Port-A/app/delete的时候,这个请求从左到右贯穿了这些服务器。

顺便一提上面的NAT Server是一台普通的服务器,我们用它做了PAT使我们的Nginx Ingress能够被外网访问到。

观察

我们使用之前提到过的Echo Server来观察透过Ingress访问Echo Server时传递给Echo Server的Request header:http://IP-A:Port-A/echo-server,得到了这些有趣的Request header:

host=IP-A:Port-A
x-original-uri=/echo-server
x-forwarded-for=IP-B
x-forwarded-host=IP-A:Port-A
x-forwarded-port=80
x-forwarded-proto=http

然后直接访问Echo Server Svc,发现是没有上面提到的x-*Request header的。于是怀疑问题出在这几个header上。

名词解释

来讲一下这些头各自代表什么意思。

  • x-forwarded-for,client访问proxy的时候,client的ip。
    在这里之所以是K8S Node的IP,是因为在Nginx Ingress看来请求是来自K8S Node的(好好看看之前提到的K8S – Using Source IP一文),在这之前的NAT它是不知道的。
  • x-forwarded-host,client访问proxy的时候,访问的原始host。
  • x-forwarded-proto,client访问proxy的时候,访问的原始http scheme。
  • x-forwarded-port,client访问proxy的时候,访问的port。
  • x-original-uri,查不到权威资料。

注意,前三个是事实标准,MDN有收录,x-forwarded-port和x-original-uri似乎是私有扩展。

实验

找一个趁手的Http Request工具(我用的是Postman),记得把Follow redirect关掉,然后模拟Nginx请求的方式(就是把上面提到的x-* header带上/去掉/修改值)直接请求App Svc。

结果发现x-forwarded-port是Response header Location的关键,即如果x-forwarded-port=Port-A的话,Location就会带上正确的端口。

分析

Redirect url是如何构造的

可以推测,App利用了host和x-forwarded-*这些header来构造redirect url。

在Java Servlet API中,在描述HttpServletResponse#sendRedirect的时候提到,其返回的URL必须是Absolute URL。

Tomcat的org.apache.catalina.connector.Response的toAbsolute方法负责构造Absolute URL。

那么它又是如何知道选用什么Port的呢?这个和RemoteIPValve有关,有兴趣的话你可以查阅相关文档。

上面只是讲了Tomcat是如何构造redirect url的,但这个方法不是标准的,不同的容器有各自的实现,毕竟Java Servlet API也没有规定如何构造Absolute URL。

我之前也写过一篇相关话题的文章《反向代理使用https协议,后台tomcat使用http,redirect时使用错误协议的解决办法》,你可以看一看。

为何x-forwarded-port是80

那么问题来了,我明明访问的是IP-A:Port-A,为何Nginx取到的值是80?

这是因为在整个请求链路的前段:NAT Server > K8S Node > Nginx Ingress Svc 都是在第4层工作的,可以认为它们干的事情都是NAT,Nginx Ingress Pod是不知道这些服务器/网络节点的端口,因此它只能把自己的端口80(容器内Port)给x-forwarded-port。

关于这个逻辑你可以查看Nginx Ingress的配置文件就能够知道了:

kubectl -n kube-system exec -it <nginx-ingress-controller-pod-name> -- cat /etc/nginx/nginx.conf

解决办法

请求时带上x-forwarded-port(不靠谱)

查看Nginx Ingress配置文件发现如果最初请求的时候带上x-forwarded-port的话,就能够改变它传递到后面的值,但是这有两个问题:

  • 通过浏览器访问时,你没有办法加上这个header
  • 这个header一般都是反向代理加的,也就是在我们的Nginx Ingress之前还得有一个反向代理

所以这个方法不好。

修改tomcat的代码(不靠谱)

虽然可以通过修改tomcat的代码,让它从x-forward-host/host header来取port,但是这个不现实。

修改NAT Server的端口为80(靠谱)

这个方法比较靠谱,只要将NAT Server的端口改成80就没有问题了。

事实上,如果你直接访问K8S Node的话(NodePort方式),也是要将NodePort设置为80,记得前面说的吗?Nginx Ingress无法知道上层NAT的端口。

总而言之,就是你最初请求的URL不能是80之外的端口,必须是http://some-ip/app才可以。

使用Nginx Ingress Annotations(靠谱)

使用Nginx Ingress提供的Proxy redirect annotations(https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#proxy-redirect),将Location的值做文本替换。

深入玩转K8S之利用Label控制Pod位置

首先介绍下什么是Label?

Label是Kubernetes系列中一个核心概念。是一组绑定到K8s资源对象上的key/value对。同一个对象的labels属性的key必须唯一。label可以附加到各种资源对象上,如Node,Pod,Service,RC等。

通过给指定的资源对象捆绑一个或多个不用的label来实现多维度的资源分组管理功能,以便于灵活,方便地进行资源分配,调度,配置,部署等管理工作。

默认配置下,Scheduler 会将 Pod 调度到所有可用的 Node。不过有些实际情况我们希望将 Pod 部署到指定的 Node,比如将有大量磁盘 I/O 的 Pod 部署到配置了 SSD 的 Node;或者 Pod 需要 GPU,需要运行在配置了 GPU 的节点上。

下面我们来实际的操作下,比如执行如下命令标注 k8s-node1 是配置了 SSD的节点。

kubectl label node k8snode1 disktype=ssd

然后通过 kubectl get node –show-labels 查看节点的 label。

未分类

可以看到disktype=ssd 已经成功添加到 k8snode1,除了 disktype,Node 还有几个 Kubernetes 自己维护的 label。有了 disktype 这个自定义 label,接下来就可以指定将 Pod 部署到 k8snod1。比如我编辑nginx.yml,增加nodeSelector标签,指定将此Pod部署到具有ssd属性的Node上去。

未分类

最后通过kubectl get pod -o wide。

如果要删除 label disktype,就执行如下命令删除即可:

kubectl label node k8s-node1 disktype-

但是要注意已经部署的 Pod 并不会重新部署,依然在 k8snode1 上运行。可能会有人说了,那怎么让Pod变回原样呢也就是分配到多个node上,那就需要一个笨方法了(至少在目前我学习的方法里面只会这样操作),就是在刚才编辑的那个nginx.yml文件里面删除nodeSelector标签,然后在利用kubectl apply重新部署,Kubernetes 会删除之前的 Pod 并调度和运行新的 Pod。

未分类

好了本次的Label标签的实践讨论到此结束,本文参考了Kubernetes 官网和每天5分钟玩转K8S。

解决 k8s 上 traefik-ingress 响应慢的问题

[摘要] 在 K8s 上配置的 traefik-ingress 作为LB,在配置 traefik-ingress 的节点上配置keepalived起VIP做高可用,可以起到app发现的功能,统一访问入口,并不需要知道后端具体启动的应用。不过测试中访问速度并不是很理想,基本每个请求都在10s左右,很是令人费解..

测试结果,测试用例是之前配置的 K8S rolling-update 的go程序:

# kubectl get pods
NAME                                   READY     STATUS    RESTARTS   AGE
glusterfs                              1/1       Running   0          3d
rolling-update-test-759964656c-dp6jj   1/1       Running   0          3d
rolling-update-test-759964656c-jtpfb   1/1       Running   0          3d
rolling-update-test-759964656c-pjgrg   1/1       Running   0          3d

# time curl -H Host:rolling-update-test.sudops.in http://172.30.0.251/
This is version 3.
real    0m11.744s
user    0m0.004s
sys 0m0.006s
#

traefik.yaml 的内容如下:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: traefik-ingress-lb
  namespace: kube-system
  labels:
    k8s-app: traefik-ingress-lb
spec:
  template:
    metadata:
      labels:
        k8s-app: traefik-ingress-lb
        name: traefik-ingress-lb
    spec:
      terminationGracePeriodSeconds: 60
      hostNetwork: true
      restartPolicy: Always
      serviceAccountName: ingress
      containers:
      - image: traefik
        name: traefik-ingress-lb
        resources:
          limits:
            cpu: 200m
            memory: 30Mi
          requests:
            cpu: 100m
            memory: 20Mi
        ports:
        - name: http
          containerPort: 80
          hostPort: 80
        - name: admin
          containerPort: 8580
          hostPort: 8580
        args:
        - --web
        - --web.address=:8580
        - --kubernetes
      nodeSelector:
        edgenode: "true"

反复查找原因,发现在其中的一台边缘节点上访问很快,基本0.0ms级的响应,其他节点均在10s左右。
网上搜了好久,终于发现有一外国哥们说是去掉对traefik-ingress-lb的资源限制看看

未分类

于是将资源的限制部分去掉(注释掉),delete 后重新 create,在任意一个节点上测试都会发现快多了。

将:
        resources:
          limits:
            cpu: 200m
            memory: 30Mi
          requests:
            cpu: 100m
            memory: 20Mi
注释掉:
        #resources:
        #  limits:
        #    cpu: 200m
        #    memory: 30Mi
        #  requests:
        #    cpu: 100m
        #    memory: 20Mi

重新创建 traefik-ingress
测试结果:
# time curl -H Host:rolling-update-test.sudops.in http://172.30.0.251/
This is version 3.
real    0m0.015s
user    0m0.006s
sys 0m0.004s
#

未分类
traefik-ingress-health

在此Mark一下。

使用Helm 在容器服务k8s集群一键部署wordpress

摘要: Helm 是啥? 微服务和容器化给复杂应用部署与管理带来了极大的挑战。Helm是目前Kubernetes服务编排领域的唯一开源子项目,做为Kubernetes应用的一个包管理工具,可理解为Kubernetes的apt-get / yum,由Deis 公司发起,该公司已经被微软收购。

Helm 是啥?

微服务和容器化给复杂应用部署与管理带来了极大的挑战。Helm是目前Kubernetes服务编排领域的唯一开源子项目,做为Kubernetes应用的一个包管理工具,可理解为Kubernetes的apt-get / yum,由Deis 公司发起,该公司已经被微软收购。Helm通过软件打包的形式,支持发布的版本管理和控制,很大程度上简化了Kubernetes应用部署和管理的复杂性。

Helm 架构

未分类

Helm 用途

做为Kubernetes的一个包管理工具,Helm具有如下功能:

  • 创建新的chart
  • chart打包成tgz格式
  • 上传chart到chart仓库或从仓库中下载chart
  • 在Kubernetes集群中安装或卸载chart
  • 管理用Helm安装的chart的发布周期

Helm有三个重要概念:

  • chart:包含了创建Kubernetes的一个应用实例的必要信息
  • config:包含了应用发布配置信息
  • release:是一个chart及其配置的一个运行实例

如何在阿里云容器服务使用Helm

阿里云容器服务的kubernets集群默认集成了helm并初始化提供了一些常用charts,下面我们就以安装wordpress示例来演示使用流程。

未分类

以上为容器服务默认提供的一些安装charts,下面我们来安装wordpress:

未分类

可以根据用户自身的需要,修改wordpress安装charts的一些默认配置,当然使用默认配置安装也是没问题的,输入本次安装release的名字,点击部署后就完成了一键部署。
我们使用控制台查看一下部署资源的情况:

未分类

可以看到wordpress的依赖资源都已经安装完毕,访问图中圈出来的地址就可以打开wordpress界面:

未分类

可以看到wordpress已经可以正常访问。如果使用传统方式,你可能需要创建一堆deployment + service + pvc等集合体,现在只需要一键部署,等待片刻,一个wordpress应用就可以展现在你面前。