• kubernetes听云实战发布版


    更多技术干货请戳:听云博客

    听云线上使用k8s已经有一段时间了,下面对一些听云使用过程中的问题进行一些梳理,包括架构设计,安装部署和后期维护。 目录结构如下:

    1.png

    下面进入正题:

    我们以听云系统的一个报表系统为例来详细进行说明:

    1.系统架构

    该应用属于Java Web报表类应用,部署在Ucloud云上。系统架构如下:

    2.png

    这是典型web应用的系统架构,在听云内部大部分应用都是此形式,对于并发量不高的业务均可参考此文档。

    基本规范:

    1.configmap用来管理配置文件

    2.deployment用来编排应用,进行升级回滚等

    3.pv用于共享存储,后端为glustefsr和nfs

    4.daemonset 用于变更不频繁,一台机器一个docker的应用

    5.nginx+ingress来做前端负载均衡和自动发现

    6.对并发要求很高的应用可以尝试用host模式,不用service做负载均衡

    2.部署说明

    参考架构图,我们需要nginx-ingress-controller 和 应用的Docker。下面分别进行详细说明。

    2.1 准备基础Docker镜像

    听云先进行应用的部署,规范是每个项目一个Docker镜像,版本号为jenkins构建的版本号。

    为了规范日后上线。我们需要按层次构建镜像,方便日后使用。

    构建基础镜像

    由于听云的项目中绝大大部分为Java项目,为了精简Docke镜像大小,基础镜像我们没有采用Centos或者Ubuntu,而是采用了alpine,该镜像只有4MB。

    Dockerfile内容如下:

    FROM registry.tingyun.com/docker.io/alpine
    MAINTAINER netop "netop@tingyun.com"
    ENV REFRESHED_AT 2016-03-18
    RUN apk add --no-cache --update-cache bash
    ENV GLIBC_PKG_VERSION=2.23-r1
    RUN apk add --no-cache --update-cache curl ca-certificates bash && 
      curl -Lo /etc/apk/keys/andyshinn.rsa.pub "https://github.com/andyshinn/alpine-pkg-glibc/releases/download/${GLIBC_PKG_VERSION}/andyshinn.rsa.pub" && 
      curl -Lo glibc-${GLIBC_PKG_VERSION}.apk "https://github.com/andyshinn/alpine-pkg-glibc/releases/download/${GLIBC_PKG_VERSION}/glibc-${GLIBC_PKG_VERSION}.apk" && 
      curl -Lo glibc-bin-${GLIBC_PKG_VERSION}.apk "https://github.com/andyshinn/alpine-pkg-glibc/releases/download/${GLIBC_PKG_VERSION}/glibc-bin-${GLIBC_PKG_VERSION}.apk" && 
      curl -Lo glibc-i18n-${GLIBC_PKG_VERSION}.apk "https://github.com/andyshinn/alpine-pkg-glibc/releases/download/${GLIBC_PKG_VERSION}/glibc-i18n-${GLIBC_PKG_VERSION}.apk" && 
      apk add glibc-${GLIBC_PKG_VERSION}.apk glibc-bin-${GLIBC_PKG_VERSION}.apk glibc-i18n-${GLIBC_PKG_VERSION}.apk
    add Shanghai /etc/localtime
    ENV LANG en_US.UTF-8

    构建镜像

    docker build -t registry.tingyun.com/common/alpine .

    push 到仓库中

    docker push registry.tingyun.com/common/alpine

    构建JDK镜像

    Dockerfile内容如下:

    FROM registry.tingyun.com/common/alpine
    MAINTAINER netop "netop@tingyun.com"
    ENV REFRESHED_AT 2016-03-14
    ADD  jdk1.7.0_45.tar.gz /opt
    ENV LANG en_US.UTF-8
    ENV JAVA_VERSION  1.7.0_45
    ENV JAVA_HOME  /opt/jdk1.7.0_45
    ENV PATH $JAVA_HOME/bin:$PATH

    该镜像只添加了一个jdk包,我们build它

    docker build -t registry.tingyun.com/common/jdk7 .
    push 到仓库中
    docker push registry.tingyun.com/common/jdk7
    构建tomcat镜像
    Docker内容如下:
    FROM registry.tingyun.com/common/jdk7
    MAINTAINER netop "netop@tingyun.com"
    ENV REFRESHED_AT 2016-03-14
    ADD  apache-tomcat-6.0.45.tar.gz /opt
    RUN ln -s /opt/apache-tomcat-6.0.45 /opt/apache-tomcat
    ADD server.xml /opt/apache-tomcat/conf/server.xml
    ENV CATALINA_HOME /opt/apache-tomcat
    ENV PATH $CATALINA_HOME/bin:$PATH
    ENV TOMCAT_MAJOR 6
    ENV TOMCAT_VERSION 6.0.45
    ENV JAVA_OPTS   -server -Djava.library.path=/opt/apache-tomcat/lib -XX:+UseConcMarkSweepGC  -XX:+PrintGCDetails  -XX:+PrintGCDateStamps -Xloggc:/opt/apache-tomcat/logs/gc.log
    WORKDIR $CATALINA_HOME
    ENV TINGYUN_APP_NAME="Java Application" 
    TINGYUN_LICENSE_KEY=f451bae910b4c3f4473e0c83d2113742
    RUN curl -o /tingyun-agent-java-latest.zip  http://download.tingyun.com/agent/java/latest/tingyun-agent-java-latest.zip
    RUN mkdir /opt/tingyun_agent;unzip /tingyun-agent-java-latest.zip -d /opt/tingyun_agent
    RUN rm /tingyun-agent-java-latest.zip -rf
    ENV CONNECTOR='<Connector port="8080" maxHttpHeaderSize="8192"    maxThreads="300" minSpareThreads="25" maxSpareThreads="300"      enableLookups="false" redirectPort="8443" acceptCount="100"     connectionTimeout="20000" disableUploadTimeout="true" />'
    ENV CONTEXT=""
    ENV ACCESS_LOG="<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"               prefix="access_log." suffix=".log"               pattern='%{X-Request-Start}i %{X-Queue-Start}i  %{X-Forwarded-For}i %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T' resolveHosts="false"/>"
    ADD run.sh /run.sh
    EXPOSE 8080
    CMD ["/run.sh"]

    run.sh内容如下:

    #!/bin/bash
    TINGYUN_AGENT_PATH="/opt/tingyun_agent/tingyun/tingyun.properties"
    TOMCAT_CONF_PATH="/opt/apache-tomcat/conf/server.xml"
    sed -i "s/Java Application/$TINGYUN_APP_NAME/"  $TINGYUN_AGENT_PATH
    sed -i "s/<%=license_key%>/$TINGYUN_LICENSE_KEY/"  $TINGYUN_AGENT_PATH
    sed -i "s#CONNECTOR#$CONNECTOR#"  $TOMCAT_CONF_PATH
    sed -i "s#CONTEXT#$CONTEXT#"  $TOMCAT_CONF_PATH
    sed -i "s#ACCESS_LOG#$ACCESS_LOG#"  $TOMCAT_CONF_PATH
    catalina.sh run

    server.xml内容如下:

    此处不贴文本了,内容为标准的server.xml 做了字符串替换。

    此处将Connector注释掉,改为CONNECTOR

    3.png

    此处将access_log和 context部分 删掉 ,替换为图片中字符串。

    4.png

    我们进行build

    docker build -t registry.tingyun.com/common/jdk7-tomcat6 .
    docker push registry.tingyun.com/common/jdk7-tomcat6

    查看该Dockerfile会注意到我们将听云Server探针进行了嵌入。是否启用探针我们会在后续的k8s配置文件进行控制,因为应用在k8s上跑具体跑在哪台机器上是不固定的,原有的zabbix jmx监控无法满足需求,我们利用听云Server来进行监控。

    2.2 利用jenkins构建应用镜像

    按照上文方式,准备好相关的基础镜像,如jdk7-tomcat6  jdk8-tomcat8等。

    下边利用jenkins来构建应用镜像。

    由于听云的jenkins本身操作系统版本太低,无法使用docker, 所以要选一台部署了docker的机器作为build机,通过ssh的方式来进行build。(此处视build的数量考虑是否需要利用jenkins slave的方式来进行build。简单测试过mesos 作为slave的方式,流程跑通,没有深测)

    听云工程师们是通过写个通用的build脚本,用来build应用的镜像。

    vi build_tomcat_docker.sh

    #!/bin/bash
    FUN_DIR=$1
    APP_DIR=$2
    PACK_NAME=$3
    PACK_MD5=$4
    APP_NAME=$5
    BASE_IMG=$6
    FINISH_IMG=$7
    BUILD_NUM=$8
    if [ -d "/data/tmp" ];then
        rm /data/tmp/* -rf 
    else
        mkdir /data/tmp -p
    fi
    if [ ! -n "$1" ] || [ ! -n "$2" ] || [ ! -n "$3" ] || [ ! -n "$4" ] || [ ! -n "$5" ] || [ ! -n "$6" ] || [ ! -n "$7" ] || [ ! -n "$8" ] ;then
        echo "build error,please input  vars"
    else
        PACK_URL=http://192.168.1.16/tingyun/${PACK_NAME}
        MD5_URL=http://192.168.1.16/tingyun/${PACK_MD5}
        /usr/bin/curl -o /data/tmp/${PACK_NAME} $PACK_URL
        /usr/bin/curl -o /data/tmp/${PACK_MD5} $MD5_URL
        MD5_ORIGN=`/usr/bin/curl $MD5_URL | awk '{print $1}'`
        MD5_WGET=`cat /data/tmp/${PACK_MD5} | awk '{print $1}'`
        if [ "$MD5_ORIGN" = "$MD5_WGET" ]; then
            echo "md5sum sucess"
            /usr/bin/unzip /data/tmp/${PACK_NAME} -d  /data/tmp/${APP_NAME}
            ADD_FILE="ADD ${APP_NAME} /opt/${FUN_DIR}/${APP_DIR}/${APP_NAME}"
            cp /data/build/Dockerfile_template /data/tmp/Dockerfile 
            sed -i "s#BASE_IMG#$BASE_IMG#" /data/tmp/Dockerfile
            sed -i "s#ADD_FILE#$ADD_FILE#" /data/tmp/Dockerfile
            docker build --no-cache=true -t  ${FINISH_IMG}:${BUILD_NUM} /data/tmp/
            docker push ${FINISH_IMG}:${BUILD_NUM}
            echo  "build img is ${FINISH_IMG}:${BUILD_NUM}"
        else
            echo "md5sum failed"
        fi  
    fi

    vim Dockerfile_template

    FROM BASE_IMG
    MAINTAINER netop "netop@tingyun.com"
    ENV REFRESHED_AT 2016-02-18
    ADD_FILE

    如果Java探针有更新,需要重新build下前边的基础镜像,在build机器上重新pull镜像后再构建应用镜像。

    打开jenkins该项目,标红处添加该行,用于记录要升级的镜像和build号

    注意命名规范:中间列是产品线。

    5.png

    添加下列用于构建镜像的机器

    6.png

    用jenkins build

    build 成功。

    7.png

    2.3 k8s配置应用

    镜像已经准备好了,接下来配置应用

    2.3.1 配置configmap

    应用的配置文件统一通过conigmap来管理

    mkdir configmap
    cd configmap
    ls -al

    8.png

    配置文件放到该目录下

    vim create_configmap.sh
    kubectl create configmap report-app-beta-config --from-file=configmap
    vim reload_configmap.sh 
    kubectl delete configmap report-app-beta-config
    kubectl create configmap report-app-beta-config --from-file=configmap

    2.3.2 配置deployment

    下面配置deployment

    vim deployment.yaml

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: report-app-beta     #应用名称
    spec:
      replicas: 10               #启动副本个数
      minReadySeconds: 60     #滚动升级时60s后认为该pod就绪
      strategy:
        rollingUpdate:
          maxSurge: 50%      #滚动升级时会先启动20%的pod
      template:
        metadata:
          labels:
            name: report-app-beta
        spec:
          volumes:
          - name: config-volume               #configmap的挂载点
            configMap:                      
              name: report-app-beta-config
          - name: pv-mapping-files             #pvc的挂载点
            persistentVolumeClaim:
              claimName: mapping-files
          nodeSelector:                     #选择调度的node节点
            zone: low
    #      hostNetwork: true
          containers:
          - name: report-app-beta
    #        livenessProbe:                  #监控
    #          httpGet:
    #            path: /healthCheck
    #            port: 8080
    #          initialDelaySeconds: 30
    #          timeoutSeconds: 10
            image: registry.tingyun.com/app/report-app:1
            command:             #小hack,为了不重打镜像,不执行默认的命令
              - sh
              - "-c"
              - ln -s /opt/mapping_files/puuid /bin/puuid && /run.sh
               env:                               #环境变量
            - name: TINGYUN_APP_NAME
              value: report-app
            - name: TINGYUN_LICENSE_KEY
              value: f451bae910b4c3f4473e0c83d2113742
            - name: JAVA_OPTS
              value: "-server -Djava.library.path=/opt/apache-tomcat/lib -Xms512m -Xmx2048m -XX:NewRatio=4 -Xss1024k  -XX:PermSize=64M -XX:MaxPermSize=256M   -XX:+UseConcMarkSweepGC  -XX:+PrintGCDetails  -XX:+PrintGCDateStamps -Xloggc:/opt/apache-tomcat/logs/gc.log -javaagent:/opt/tingyun_agent/tingyun/tingyun-agent-java.jar -Duser.language=zh -Duser.region=CN -Duser.timezone=GMT+08 -DappName=report-app"
            - name: CONNECTOR
              value: '<Connector port="8080" maxHttpHeaderSize="8192"    maxThreads="300" minSpareThreads="25" maxSpareThreads="300"      enableLookups="false" redirectPort="8443" acceptCount="100"     connectionTimeout="20000" disableUploadTimeout="true" /> '
            - name: CONTEXT
              value: '<Context path="/mobile" reloadable="false" allowLinking="true"  docBase="/opt/tingyun/report-app/webapp/" workDir="/opt/tingyun/report-app/work/"/>   '
            ports:
             - containerPort: 8080
            volumeMounts:                     #上边的挂载点挂载到容器中的路径
            - name: config-volume                           
              mountPath: /opt/tingyun/report-app/conf      
            - name: pv-mapping-files
              mountPath: /opt/mapping_files

    kubectl create -f deployment.yaml

    kuectl get pods 

    看pod已经起来了

    9.png

    2.3.3 配置Service

    下面配置service

    vim service.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: report-app-beta
      labels:
        name: report-app-beta
    spec:
     # sessionAffinity: ClientIP   #在基于新的nginx-ingress-controller已经不需要配置该项,session绑定在nginx处配置
      ports:
        - port: 8080
      selector:
        name: report-app-beta

    kubectl create -f service.yaml

    kubectl get service

    10.png

    2.3.4 配置ingress

    下面配置ingress

    vim ingress.yaml
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: report-app-beta
    spec:
      rules:
      - host: report-beta.tingyun.com     #域名
        http:
          paths:
          - path: /mobile               #访问路径
            backend: 
              serviceName: report-app-beta    #service名称
              servicePort: 8080              #service端口

    kubectl create -f ingress.yaml

    kubect get ingress

    10.png

    2.4 创建nginx-ingress-controller

    nginx-ingress-controller  需要监听宿主机的80端口,固定在某几台机器上,为此需要给相关node 定义标签。

    kubectl label nodes ucd-ty-k8s-node-001.ucd.tingyun.com role=nginx-lb

    kubectl get nodes --show-labels

    创建configmap

    vim nginx.tmpl

    该文件可以去github上下载

    https://github.com/kubernetes/contrib/blob/master/ingress/controllers/nginx/nginx.tmpl

    kubectl create configmap nginx-template --from-file=nginx.tmpl=nginx.tmpl

    为了将为所有在nginx后的项目开启session保持,同时听云的开发工程师要打开后端监控页面,需要修改两个地方。

    1.png

    这里暂时先改为无论如何都启用session保持

    2.png

    这里直接启用traffic_status

    vim rc.yaml

    该文件可以去github下载

    https://github.com/kubernetes/contrib/blob/master/ingress/controllers/nginx/examples/full/rc-full.yaml

    kubectl create rc.yaml

    查看nginx_status界面

    http://10.10.228.175:8080/nginx_status

    1.png

    接下来即可访问该项目

    2.png

    原文链接:http://blog.tingyun.com/web/article/detail/825

  • 相关阅读:
    java ->IO流_打印流
    java ->IO流_序列化流与反序列化流
    java ->properties类
    java ->String、StringBuffer、StringBuilder三者之间的区别
    java-> 利用IO操作与递归实现目录的复制
    java
    java ->IO流_转换流
    java ->IO流_字符流
    java ->IO流_字节流
    死循环
  • 原文地址:https://www.cnblogs.com/TingyunAPM/p/5604663.html
Copyright © 2020-2023  润新知