jasonzhuo

 

 (来自DockOne社区的分享)

1,我们为什么要用k8s

1.1 拥抱微服务
微服务架构将巨大单体式应用分解为多个服务,每个服务通过 RPC 或者API 进行通信,具备了各个自服务容易开发、维护的优点,另外子服务还具备独立部署、快速扩展等优点。Kubernetes 对微服务本身有很好的支持,应用本身通过Deployment 进行部署,各个服务运行在 Pod 中,Pod 之间服务通过 Service 具备的服务发现实现相互间的通信。同时微服务架构也恰好是云原生应用的一种体现。

1.2 容器编排
Kubernetes 帮助使用者通过简单易用的 API 高效地管理成千上万个运行在
容器中的微服务。Kubernetes 在 1.6 版本中已经支持 5000 个节点,这也说明 Kubernetes具备大规模集群的编排管理能力。同时,Kubernetes还具备包括监控、日志、包管理等各种完善而专业的工具链,这将大大减轻运维和开发人员的负担。

1.3 服务注册发现
微服务的实践过程中存在各种服务依赖关系,因此服务的注册发现十
分重要。Kubernetes 对服务进行抽象,通过抽象的服务层动态地解析到对应的容器服务。Kubernetes 同时提供了 DNS 和环境变量两种方式,帮助实现服务的注册和发现,Kubernetes 早期版本中使用的环境变量方式实现,现在 Kubernetes 则默认使用 DNS,通过使用 DNS 将服务名称解析为服务的 IP 地址,然后 Proxy 转到对应的 Pod

1.4 主机资源利用率
K8s对主机的资源利用率,也是一种提升,基本上物理机,ECS,EC2,主机的利用率通常都在30%左右,极大的浪费了资源。使用k8s后,可以根据主机资源使用情况,自动的调度pod运行到那台机器上。可以极大的提高主机的资源利用率

1.5 弹性扩容
      例如我们新上线的应用,因不同的业务场景,初次上线的时候不太确定给多少资源,默认就给应用4G内存,在k8s中我们可以根据内存的使用率,来定义是否启动一个新的pod,以及pod最少多少个,最多多少个

1.6 应用横向扩展
例如我们应用在在访问资源高峰期,应用需要进行添加机器,如果在ECS,EC2等机器,就需要在安装服务呀,配置负载之类的,在容器中就简单多了,直接修改ReplicaSet
 修改节点数量,就会根据镜像自动启动新服务

安装步骤大致分为
2.1 安装ansible
  2.2 集群配置,修改镜像源
  2.3 部署k8s集群
  2.4 安装svc  ingress
  2.5 安装helm
  2.6 添加节点
 会单独在给一个安装文档,文档格式是markdown,将文档用txt打开,然后全文粘贴,在百度搜索markdown在线编辑,然后粘贴进去阅读即可

推荐网址  https://www.zybuluo.com/mdeditor#1407318

接下来是第二部分,安装k8s
2,使用kubespray安装kubernetes
使用kubespray 安装kubernetes 比常规要方便很多,配置完ssh-key后,直接使用ansible 就可以快速的添加节点,删除节点

| 节点 | 公网IP|内网IP | 角色 |
| ------ | ------ | ------ |------ |
| master1 | 0.0.0.0 |172.16.199.169 | master+etcd|
| master2 | 0.0.0.0 | 172.16.199.168| master+etcd |
| master3 | 0.0.0.0 | 172.16.199.167|master+etcd |
| node1 | 0.0.0.0 |172.16.199.166  |node |
| node2 | 0.0.0.0 | 172.16.199.165 | ansible |

----
##安装k8s
#####基础准备
```
安装ansible
yum -y install ansible git
yum install -y python-pip python-netaddr ansible git
pip install --upgrade Jinja2
配置公钥互信,修改主机名。添加到/etc/hosts

```

######克隆代码
```
git clone https://github.com/kubernetes-incubator/kubespray.git
cd kubespray
git checkout v2.4.0 -b myv2.4.0
cp inventory/inventory.example inventory/inventory.cfg
```
#####修改ansible机器
```
vim inventory/inventory.cfg
 
[all]
master1 ansible_ssh_host=172.16.199.169 ip=172.16.199.169
master2 ansible_ssh_host=172.16.199.168 ip=172.16.199.168
master3 ansible_ssh_host=172.16.199.167 ip=172.16.199.167
node1 ansible_ssh_host=172.16.199.166 ip=172.16.199.166
[kube-master]
master1
master2
master3
[etcd]
master1
master2
master3
[kube-node]
node1
[k8s-cluster:children]
kube-node
kube-master
```
#####集群配置
```
cp inventory/group_vars/all.yml inventory/group_vars/all.yml.bak
cp inventory/group_vars/k8s-cluster.yml inventory/group_vars/k8s-cluster.yml.bak
vi inventory/group_vars/all.yml  
bootstrap_os: centos  #指定操作系统为 centos
vi inventory/group_vars/k8s-cluster.yml 
flannel  # 指定网络方案
kube_network_plugin: flannel # 默认关闭 dashboard dashboard_enabled: false
```
#####修改镜像源
```
vi roles/download/defaults/main.yml
etcd_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/etcd"
flannel_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/flannel" 
flannel_cni_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/flannel-cni" 
hyperkube_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/hyper-kube"
pod_infra_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/pause-amd64"
nginx_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/nginx"
kubedns_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/k8s-dns-kube-dns-amd64"
dnsmasq_nanny_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/k8s-dns-dnsmasq-nanny-amd64"
dnsmasq_sidecar_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/k8s-dns-sidecar-amd64" 
kubednsautoscaler_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/cluster-proportional-autoscaler-amd64"
```

```
vi roles/kubernetes-apps/ansible/defaults/main.yml
kubedns_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/k8s-dns-kube-dns-amd64" 
dnsmasq_nanny_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/k8s-dns-dnsmasq-nanny-amd64"
dnsmasq_sidecar_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/k8s-dns-sidecar-amd64" 
kubednsautoscaler_image_repo: "registry.cn-hangzhou.aliyuncs.com/linkcloud/cluster-proportional-autoscaler-amd64"
```
#####ansible 部署 预计1小时

```
部署会有失败的现象,请多等待,因为还会拉去国外地址的源
ansible-playbook -b -i inventory/inventory.cfg cluster.yml --flush-cache
```
#####安装serviceaccount
```
vim sa.yml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
```
```
kubectl apply -f sa.yml
```
####安装ingress

```
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app: nginx-ingress
    heritage: Tiller
    release: nginx-ingress-0
  name: nginx-ingress-0-nginx-ingress
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app: nginx-ingress
    heritage: Tiller
    release: nginx-ingress-0
  name: nginx-ingress-0-nginx-ingress
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  - endpoints
  - nodes
  - pods
  - secrets
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - list
  - update
  - watch
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
- apiGroups:
  - extensions
  resources:
  - ingresses/status
  verbs:
  - update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app: nginx-ingress
    heritage: Tiller
    release: ungaged-bear
  name: nginx-ingress-0-nginx-ingress
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-0-nginx-ingress
subjects:
- kind: ServiceAccount
  name: nginx-ingress-0-nginx-ingress
  namespace: default
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  labels:
    app: nginx-ingress
    component: controller
    heritage: Tiller
    release: nginx-ingress-0
  name: nginx-ingress-0-nginx-ingress-controller
spec:
  selector:
    matchLabels:
      app: nginx-ingress
      component: controller
      release: nginx-ingress-0
  template:
    metadata:
      labels:
        app: nginx-ingress
        component: controller
        release: nginx-ingress-0
    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --default-backend-service=default/nginx-ingress-0-nginx-ingress-default-backend
        - --election-id=ingress-controller-leader
        - --ingress-class=nginx
        - --configmap=default/nginx-ingress-0-nginx-ingress-controller
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        image: registry.cn-hangzhou.aliyuncs.com/licheng/nginx-ingress-controller:0.21.0
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: nginx-ingress-controller
        ports:
        - containerPort: 80
          hostPort: 80
          name: http
          protocol: TCP
        - containerPort: 443
          hostPort: 443
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      hostNetwork: true
      restartPolicy: Always
      serviceAccount: nginx-ingress-0-nginx-ingress
      serviceAccountName: nginx-ingress-0-nginx-ingress
      terminationGracePeriodSeconds: 60
  templateGeneration: 1
  updateStrategy:
    type: OnDelete
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  labels:
    app: nginx-ingress
    component: default-backend
    heritage: Tiller
    release: nginx-ingress-0
  name: nginx-ingress-0-nginx-ingress-default-backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-ingress
      component: default-backend
      release: nginx-ingress-0
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: nginx-ingress
        component: default-backend
        release: nginx-ingress-0
    spec:
      containers:
      - image: docker.io/mirrorgooglecontainers/defaultbackend:1.4
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        name: nginx-ingress-default-backend
        ports:
        - containerPort: 8080
          protocol: TCP
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 60
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-ingress
    component: controller
    heritage: Tiller
    release: nginx-ingress-0
  name: nginx-ingress-0-nginx-ingress-controller
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  - name: https
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    app: nginx-ingress
    component: controller
    release: nginx-ingress-0
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx-ingress
    component: default-backend
    heritage: Tiller
    release: nginx-ingress-0
  name: nginx-ingress-0-nginx-ingress-default-backend
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: nginx-ingress
    component: default-backend
    release: nginx-ingress-0
  type: ClusterIP
```
```
然后kubectl apply -f ingress.yml

docker pull registry.cn-hangzhou.aliyuncs.com/licheng/nginx-ingress-controller:0.21.0
```

####安装helm
```
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
```
```
./get_helm.sh
helm init
kubectl get pod -n kube-system
```
####添加Node
```
vi inventory/inventory.cfg
[all]
master1 ansible_ssh_host=172.16.199.169 ip=172.16.199.169
master2 ansible_ssh_host=172.16.199.168 ip=172.16.199.168
master3 ansible_ssh_host=172.16.199.167 ip=172.16.199.167
node1 ansible_ssh_host=172.16.199.166 ip=172.16.199.166
node2 ansible_ssh_host=172.16.199.165 ip=172.16.199.165
[kube-master]
master1
master2
master3
[etcd]
master1
master2
master3
[kube-node]
node1
node2
[k8s-cluster:children]
kube-node
kube-master
```
```ansible-playbook -i inventory/inventory.cfg scale.yml -b -v ```

  

 3.1 如何建设devops 平台
Devops 平台整体架构如下
部署流程的优化

  我们最早也是常规的Nginx+tomcat、LAMP、LNMP平台, 后来因服务器数量众多,服务器多数靠各项目的开发进行管理,没有统一的CMDB,同时服务器资源利用率也不高,有很大的资源闲置和资源浪费。我们是从18年8月份开始使用容器的。目前60%的业务都运行在容器平台上。其余的业务正在向容器云平台迁移中。

接下来是第三部分  3, 我们使用容器云平台原因

整体的架构流程如下

           

右边是自研的监控告警系统和运维对接平台,包括监控平台、日志平台和运维 CMDB 等系统

我们建设基于Kubernetes容器云平台,目标就是希望能够提高研发人员从代码构建到业务上线的整体效率。这个过程是一个完整的 CI/CD 流程,包括从开发人员提交代码,进行代码 Review,到代码编译、单元测试、集成测试,最后构建出业务镜像,在不同的环境中部署业务,上下线服务等各个环节,形成统一的应用生命周期管理

左侧是持续集成框架,其中由应用基线管理、代码编译、单元测试、冒烟测试、发布系统等模块组成。中间是多集群统一管理平台。业务会分别在开发、预发和生成三个不同的环境中部署。业务的最上层是由 SLB 软负载统一管理 DNS、Nginx、LVS 等组件,将业务流量转发给不同Kubernetes 集群中的业务容器。基于 Kubernetes 的 CaaS 由多集群管理、镜像管理、权限管理、服务发现等子模块组成。

 3.4 服务发现

  我们是在各个项目中,单独引用了一个自己写的jar包,在jar包中定义了注册中心地址。然后各个项目引入jar包,通过Jar中定义的地址去连接

3.2 镜像管理  
  我们是使用的自建的Harbor作为自己的镜像仓库, 是在阿里云购买的ECS, 我们的服务都是基于jdk, tomcat, nginx, php, nodejs, 等基础镜像起来的, 我们运维只需要维护这几个基础镜像就可以

3.3 权限管理
  用户的容器集群由权限模块进行管理, 目前提供给开发的只有日志查询权限, 账号与公司的LDAP 对接。目前暂不支持虚拟账户的认证

 3.5 稳定性
  目前我们容器云平台,dev环境是自建的,UAT和PRO都是使用的阿里云。关于容器监控我们额外做了prometheus + alerting 并关联钉钉机器人和微信报警。除了应用本身的错误外,整个容器云平台没有出现过因服务类的down机情况

 3.6.2 弹性能力。电商行业的特征决定了每年都会出现618,双11,双12等峰值流量。因为,在大促销期间动态的租用公有云服务,在平时只保留满足日常流量的机器即可

  3.6 成本
  降低机器成本和运维成本是一项长期艰苦的工作,我们在迁入容器云的过程中发现资源利用较好的两种情况。

 3.6.1 混合调度。我们在提高容器部署的密度后,对业务带来的好处就是快速扩展和资源混合利用,我们多条线的pod会集中在一台实例中,可以很好的提高单机资源利用率

接下来是第四部分  4,我们现在的微服务架构

基本上也是多数公司的微服务架构,是通过 zuul + eureka + apollo 来完成了,eureka本身有个监测心跳机制,例如我的容器A1, A2 注册到了eureka, 此时要部署容器,例如新部署的容器要B1,B2,在健康检查完全通过后, A1,A2已经被替换掉。在k8s层面做到了无缝切换, 但是 eureka 本身还会将A1,A2保留约2分钟。也就是这个时间内,eureka(注册中心)会同时存在4个pod

可以代替掉传统网关

我们现在正在替换掉eureka,向istio 迁移
  Istio 同时也具备
统一的入口
   动态服务发现和路由规则
   负载均衡
   策略和请求tracing
   熔断器
   健康检查,基于百分比流量拆分和灰度发布
   认证和鉴权

在这个时间点通过zuul来访问服务的话,则会有50%的请求发布到老地址上去。老地址容器此时已经被销毁,访问则会报出502,504等错误。荐更换掉eureka。使用istio,istio可以避免这个问题。

 

分类:

技术点:

相关文章: