实战交付dubbo服务到k8s

一、什么是Dubbo是什么

●   Dubbo是什么
     ●   Dubbo基于java开发的,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提
         供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。
     ●   Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA
         服务治理方案。
     ●   简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布
         式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东东,说白
         了就是个远程服务调用的分布式框架

●   Dubbo能做什么
     ●   透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API
         侵入。
     ●   软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
     ●   服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者
         的IP地址,并且能够平滑添加或删除服务提供者。

服务发现依赖于注册中心,不管是消费者还是提供者都需要连接注册中心,提供者去注册中心里面注册的过程叫注册,消费者去连接注册中心的过程叫做订阅。这样Consumer跟Provider都连接了注册中心,这时候Consumer通过invokre(RPC协议,远程过程调用)去调用一个Provider服务的一个方法,就好像Consumer调用自己本地的方法一样
为什么要用dubbo:
一个网站界面或者说一个前台的web工程,此页面里面可能有商品的浏览页、会员、个人用户中心、抽奖活动等等,各自的模块,我们以Consumer消费者代替(浏览页Consumer、会员Consumer等等)。这些页面的各个模块,需要调用后台不同的API接口,各个api我们以Provide生产者代替(浏览页Provide、会员Provide等等)。假如我们把整个前台页面代码,和后台实现的api口,都封装在一套代码中,势必就存在如果本地资源无线扩涨,根本不利于横向扩容(比如促销活动只是需要访问大量的抽奖活动,其他的页面模块访问量并不大,怎么办,加机器做负载么,代码都在一起,全部代码在跑一遍?负载怎么做)。所以势必要更换框架,更换机制,把后台的各种api接口跟前台代码就行解耦(每个程序之间的关联程度,叫做耦合度,上述描述中都卸载一套程序,只要改了一个地方,可能其他的地方也要跟着改,这就叫做耦合度高,所以我们要接触耦合度高,让代码分开,叫做解耦)。
dubbo的机制:
思考:会员、积分、消费页面等等都进行了代码解耦后,直接前台连接后台api就行了,注册中心、服务发现又是什么?如果一个客户在网站买一个商品,他会经历下单结算界面(使用了优惠券),点击支付的时候,后台会先去验证消费券并给当前用户删除这个消费卷,然后再返回支付的界面成功,消费券也会删除。这一套流程看似没问题,但是如果在流量高峰期,就会卡的不要不要的。为了解决这种情况,引入了注册中心,消费者Consumer(各个前台页面的代码)去向注册中心提交自身信息(过程叫订阅),告知有我这个页面,而提供者Provide(各个后台的api接口)也向注册中心提交自身信息(过程叫注册),告知有那些api的接口。然后有意思的来了,还是客户在网站买一个商品,经历下单结算界面(使用了优惠券),会把这些信息告诉注册中心,由于其他的api接口实时的在监听中心注册的变化,所以api进行了服务的自动发现,简称服务发现,这些对应的api接口,发现一个Consumer的服务请求,并对应的优惠券、结算页面同时,获取了信息,所以同时处理请求谁也不会卡着谁。所以使用不同Provider方法(API接口),让Consumer调用不同的一个单独的独立服务,就好像调用自己本地的方法一样。
Monitor 监控中心:可以监控发现有多少个Consumer消费者、多少个Provide提供者,他们之间怎么关联的、存在什么问题。
所以交付Dubbo微服务流程:第一交付Registry注册中心、第二交付Provider提供者、第三交付Monitor监控中心、第四交付Consumer消费者

二、Dubbo部署k8s中实验架构图

1、交付zoopkeeper
图中zk1、zk2、zk3,全名zoopkeeper,Dubbo微服务的注册中心依赖于zk(zoopkeeper)来实现的,用来存储生产者、消费者、dubbo运行过程中的一些信息。最低由三个zoopkeeper实现集群做高可用,他跟etcd注册中心机制一样有leader,leader死了留遗言下一个谁是leader。其他的注册中心软件比如:Eureka、etcd、zoopkeeper、Consul底层原理一样,开发语言不同而已

2、交付Consumer消费者集群、Provider提供者集群
下面是要部署在k8s内部的集群

有Dubbo微服务的Consumer消费者集群,有Dubbo微服务的Provider提供者集群,最后都都封装成pod交付到k8s里,其中把商品、抽奖活动、等等封装成各自的pod。为什么把Consumer、Provider做成pod方便扩容(比如到秒杀环节,有大量的收银、订单中心请求,大量用户一瞬间挤进来。前台web(consumer消费者)能扛得住,但是调用对应的后端服务(Provider生产者)扛不住,因为后端要连接数据库,会有延迟,产生瓶颈,所以就需要有方法扩容,把这种能动态扩容的服务,统统放到k8s中,实现动态扩容、迁移等等,管理Dubbo微服务。)

3、交付Dubbo-Monitor监控中心到k8s中,其他组件dubbo-admin也可实现

4、开发提交代码到git,使用jenkins编译成imgae后推送到harbor,通过image交付到k8s
尽量模拟生产环境,所以开发写完代码会把代码提交到git、或者svn代码版本控制中心,运维使用恰当的工具,比如jenkins进行持续继承(就是把代码从git拉取下来,自动化把代码进行编译,然后打成image镜像,自动推送到harbor私有仓库),图中ops服务器就是hdss7-200(DevOps是为了填补开发端和运维端之间的信息鸿沟,所以ops服务器就是开发跟研发对接的一个服务器),通过image配置资源配置清单,应用到k8s,pod启动后自己会找注册中心,进行注册

注释:

1、用户通过ingress资源配置好规则,找到消费者集群的pod,因为消费者集群对应的是web服务,消费者去找对应的提供者集群,获取对应的信息返回到消费者后,消费者把对应的流量反馈给用户

2、Dubbo 可以部署多个消费者、多个生产者,生产中100~200左右属于在正常不过

3、其中把zoopkeeper放在k8s的外部,不要部署在k8s集群中,因为zoopkeeper是典型的有状态服务,但有状态的也可以服务部署在k8s中,但还是不建议。
解释:k8s有很强的动态性,可以飘逸、扩容、缩容、删除、重建、自愈机制,所以要求pod管理的一定是没有状态的资源。有状态服务:etc、zoopkeeper、mysql、ES、MQ缓存(MQ缓存比如redis还好,应用到k8s中,可以落盘可以做持久化,但是缓存的数据不会保证,随着pod宕机会没,如果觉的什么都不能丢,使用关系型数据库)。没有状态:随便飘逸,随便宕机、不依赖于其他。但是也不是说mysql这种有状态的不能承载pod中,有专门的pod控制器StatefulSet进行管理,比如部署 MySQL,启动一片mysql,应该先启动那个,在启动那个,主、从配置有什么差别,应该什么主从关系,StatefulSet进行声明。

4、其中jenkins也是有状态的服务,只不过把有状态的那部分存储给挂在出来到本地,但是也不能扩容成两份,除非做主从。

三、部署zoopkeeper集群

     ●   Zookeeper是Dubbo微服务集群的注册中心
     ●   它的高可用机制和K8S的etcd集群一致
     ●   由Java编写,所以需要jdk环境

ZK集群是有状态的服务,跟ETCD运行方式类似,要求集群节点是不低于3的奇数个,然后进行选举Leader。

主机

IP地址

角色

hdss7-11

10.4.7.11

zk1

hdss7-12

10.4.7.12

zk2

hdss7-21

10.4.7.21

zk3

在hdss7-11、hdss7-12、hdss7-21 都需要操作

1、JDK配置

1.1、下载JDK

https://download.oracle.com/otn/java/jdk/8u231-b11/5b13a193868b4bf28bcb45c792fce896/jdk-8u231-linux-x64.tar.gz

1.2、安装JDK

1、解压JDK
[root@hdss7-11 ~]# mkdir -p /opt/src;cd /opt/src
[root@hdss7-11 src]# rz jdk-8u231-linux-x64.tar.gz
[root@hdss7-11 src]# mkdir -p /usr/java/
[root@hdss7-11 src]# tar zxvf jdk-8u231-linux-x64.tar.gz -C /usr/java/
[root@hdss7-11 ~]# cd /usr/java/
[root@hdss7-11 java ]# ln -s jdk1.8.0_231/ jdk

2、java做环境变量
[root@hdss7-11 java]# vi /etc/profile     # 在profile文件末尾追加如下配置

export JAVA_HOME=/usr/java/jdk
export PATH=$JAVA_HOME/bin:$JAVA_HOME/bin:$PATH
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar

[root@hdss7-11 java]# source /etc/profile
[root@hdss7-11 java]# echo $CLASSPATH
:/usr/java/jdk/lib:/usr/java/jdk/lib/tools.jar

[root@hdss7-11 java]# echo $PATH
/usr/java/jdk/bin:/usr/java/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

[root@hdss7-11 java]# java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)
 

2、安装zoopkeeper

[root@hdss7-11 opt]# cd /opt/src
[root@hdss7-11 src]# wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
[root@hdss7-11 src]# tar -xf zookeeper-3.4.14.tar.gz -C /opt/
[root@hdss7-11 src]# cd /opt/
[root@hdss7-11 opt]# ln -s zookeeper-3.4.14/ zookeeper
[root@hdss7-11 opt]# mkdir -p /data/zookeeper/data /data/zookeeper/logs
[root@hdss7-11 zookeeper]# vim /opt/zookeeper/conf/zoo.cfg  # 配置zookeeper的配置文件

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/logs
clientPort=2181
server.1=zk1.od.com:2888:3888
server.2=zk2.od.com:2888:3888
server.3=zk3.od.com:2888:3888

解释:
server.1=zk1.od.com:2888:3888    # 把zookeeper服务的做成了dns,所以还要做dns解析
server.2=zk2.od.com:2888:3888    # zk1对应10.4.7.11     zk2对应10.4.7.12
server.3=zk3.od.com:2888:3888    # zk3对应10.4.7.21


在hdss7-11操作

3、配置DNS解析

[root@hdss7-11 named]# vi /var/named/od.com.zone

$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2020010505 ; serial
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
$TTL 60 ; 1 minute
dns                A    10.4.7.11
harbor             A    10.4.7.200
k8s-yaml           A    10.4.7.200
traefik            A    10.4.7.10
dashboard          A    10.4.7.10
zk1                A    10.4.7.11
zk2                A    10.4.7.12
zk3                A    10.4.7.21

解释:
2020010505 ; serial   序列号前滚一位
zk1                A    10.4.7.11    添加
zk2                A    10.4.7.12    添加
zk3                A    10.4.7.21    添加

[root@hdss7-11 named]# systemctl restart named
[root@hdss7-11 named]# dig -t A zk1.od.com @10.4.7.11 +short
10.4.7.11

在hdss7-11、hdss7-12、hdss7-21 都需要操作

4、配置myld

只有创建了myld,才能实现把7-11、7-12、7-21三个节点的zookeeper做成集群,区分作用跟谁是主节点无关

[root@hdss7-11 named]# echo 1 > /data/zookeeper/data/myid
[root@hdss7-12 named]# echo 2 > /data/zookeeper/data/myid
[root@hdss7-21 named]# echo 3 > /data/zookeeper/data/myid

5、启动zookeeper

[root@hdss7-11 ]# /opt/zookeeper/bin/zkServer.sh start
[root@hdss7-12 ]# /opt/zookeeper/bin/zkServer.sh start
[root@hdss7-21 ]# /opt/zookeeper/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

[root@hdss7-11 named]# ps aux |grep zookeeper

root      19691  7.2  4.7 2284764 47048 pts/0   Sl   16:17   0:01 /usr/java/jdk/bin/java -Dzookeeper.log.dir=. -Dzookeeper.root.logger=INFO,CONSOLE -cp /opt/zookeeper/bin/../zookeeper-server/target/classes:/opt/zookeeper/bin/../build/classes:/opt/zookeeper/bin/../zookeeper-server/target/lib/*.jar:/opt/zookeeper/bin/../build/lib/*.jar:/opt/zookeeper/bin/../lib/slf4j-log4j12-1.7.25.jar:/opt/zookeeper/bin/../lib/slf4j-api-1.7.25.jar:/opt/zookeeper/bin/../lib/netty-3.10.6.Final.jar:/opt/zookeeper/bin/../lib/log4j-1.2.17.jar:/opt/zookeeper/bin/../lib/jline-0.9.94.jar:/opt/zookeeper/bin/../lib/audience-annotations-0.5.0.jar:/opt/zookeeper/bin/../zookeeper-3.4.14.jar:/opt/zookeeper/bin/../zookeeper-server/src/main/resources/lib/*.jar:/opt/zookeeper/bin/../conf::/usr/java/jdk/lib:/usr/java/jdk/lib/tools.jar -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /opt/zookeeper/bin/../conf/zoo.cfg
root      19795  0.0  0.0 112828   968 pts/0    S+   16:17   0:00 grep --color=auto zoo
[root@hdss7-11 named]# netstat -tulpn |grep 2181   # zookeeper默认启动2181,所以不管是消费者还是生产者,都要跟集群的2181连接
tcp6       0      0 :::2181                 :::*                    LISTEN      19691/java          

6、查看领导者

查看集群状态,如下这种说明已经是集群了,leader主节点,follower从节点

[root@hdss7-11 named]# /opt/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: follower

[root@hdss7-12 opt]#  /opt/zookeeper/bin/zkServer.sh status      
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: leader  

[root@hdss7-21 opt]#  /opt/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: follower

7、自启动

在hdss7-11、hdss7-12、hdss7-21 都需要操作

1.进入到/etc/init.d目录下,新建一个zookeeper脚本
[root@hdss7-11 named]# cd /etc/init.d
[root@hdss7-11 /init.d]# vi zookeeper     # service服务启动 /etc/init.d/ 目录下的脚本

#!/bin/bash    
#chkconfig:2345 20 90    
#description:zookeeper    
#processname:zookeeper    
export JAVA_HOME=/usr/java/jdk
case $1 in    
        start) su root /opt/zookeeper/bin/zkServer.sh start;;    
        stop) su root /opt/zookeeper/bin/zkServer.sh stop;;    
        status) su root /opt/zookeeper/bin/zkServer.sh status;;    
        restart) su root /opt/zookeeper/bin/zkServer.sh restart;;    
        *) echo "require start|stop|status|restart" ;;    
esac

解释:

脚本很简单,运行脚本并给赋予一个$1,脚本中获取的$1如果是start,就启动、获取的$1如果是stop,就停止。

2.给脚本添加执行权限
[root@hdss7-11 /init.d]# chmod +x zookeeper

3.通过service命令启动、停止、重启脚本、查看状态
使用service zookeeper start/stop命令来尝试启动关闭zookeeper,使用service zookeeper status查看zookeeper状态。或者直接 zookeeper start/stop/status

4.添加到开机启动
[root@hdss7-11 /init.d]# chkconfig --add zookeeper

5.查看开机自启的服务中是否已经有我们的zookeeper

[root@7-11 init.d]# chkconfig --list zookeeper

Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use 'systemctl list-unit-files'.
      To see services enabled on particular target use
      'systemctl list-dependencies [target]'.

zookeeper       0:off   1:off   2:on    3:on    4:on    5:on    6:off

四、安装部署jenkins

Jenkins是一款由Java编写的开源的持续集成工具。它运行在java的Servlet容器中(例如Apache Tomcat),注意java的Servlet容器,并不是k8s的容器。Servlet、Servlet容器等内容讲解。它支持软件配置管理(SCM)工具(包括AccuRev SCM、CVS、Subversion、Git、Perforce、Clearcase和RTC),可以执行基于Apache Ant和Apache Maven的项目,以及任意的Shell脚本和Windows批处理命令。Jenkins是一个有状态的应用,如果托管在K8S中,只运行一个副本,且需要持久化存储。
官网:Jenkins
下载地址:Jenkins 的安装和设置
官方文档:https://jenkins.io/zh/doc/

在hdss7-200 操作

1、下载Jenkins官方镜像

官方jenkins:2.190.3

[root@hdss7-200 ~]# docker pull jenkins/jenkins:2.190.3
[root@hdss7-200 ~]# docker image ls |grep jenkins
jenkins/jenkins                                                      2.190.3                         22b8b9a84dbe        13 months ago       568MB
[root@hdss7-200 ~]# docker tag 22b8b9a84dbe harbor.od.com:180/public/jenkins:v2.190.3
[root@hdss7-200 ~]# docker login harbor.od.com:180
[root@hdss7-200 ~]# docker push harbor.od.com:180/public/jenkins:v2.190.3

2、制作Jenkins镜像

2.1、自定义Dockerfile

注意官方jenkins不能直接使用,需要用自定义Dockerfile对官方的jenkins镜像做一些改变,加上如何拉取镜像,登录使用什么账户等

[root@hdss7-200 ~]# mkdir -p /data/dockerfile/jenkins/
[root@hdss7-200 ~]# cd /data/dockerfile/jenkins/
[root@hdss7-200 jenkins]# vim Dockerfile  # 该脚本主要是docker-ce源中安装了一个docker-ce-cli

# 修改默认的 Jenkins 镜像
FROM harbor.od.com:180/public/jenkins:v2.190.3
USER root
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
ADD id_rsa /root/.ssh/id_rsa
ADD config.json /root/.docker/config.json
ADD get-docker.sh /get-docker.sh
RUN echo "      StrictHostKeyChecking no" >> /etc/ssh/ssh_config && sh /get-docker.sh ; rm -f get-docker.sh

解释:
FROM harbor.od.com:180/public/jenkins:v2.190.3   使用的是harbor的jenkins:v2.190.3 
USER root   声明root,启动docker的时候要用root用户启动,默认docker是普通用户

RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone   执行cp 把Asia/Shanghai 放到了/etc/下并重命名localtime,也就是说把docker的时区改成东八区,jenkins是外国人开发的,所以默认镜像里面的时间为UTC时间

ADD id_rsa /root/.ssh/id_rsa    物理机hdss7-200生成一对ssh密钥,把私钥拷贝到容器,到时候gitee上存放hdss7-200的公钥,这样docker容器才能拉取代码。是这样的Dubbo服务中消费者是git ssh拉取代码,git克隆拉代码,两种方式:(1、httrp协议  2、ssh),如果走ssh必须生成密钥对,把私钥封装在docker镜像里面,把公钥放到git仓库,这样docker就能从git拉取到镜像

ADD config.json /root/.docker/config.json 只要运行了一次docker login harbor.do.com:180并登录成功了,就会在本地生成/root/.docker/config.json文件,里面记录了你登录的信息,记录了登录账户密码,下次再登录的时候,就不用输入账户密码。所以config.json是登录远程仓库的认证信息,里面有user\username\passwd,jenkins要打包成docker镜像,并推送到harbor仓库里面,就必须要先登录harbor仓库,把物理机7-200的/root/.docker/config.json拷贝带容器中,容器直接可以登录harbor仓库

[root@hdss7-200 jenkins]# cat /root/.docker/config.json 
{
    "auths": {
        "harbor.od.com:180": {
            "auth": "YWRtaW46SGFyYm9yMTIzNDU="
        }
    },
    "HttpHeaders": {
        "User-Agent": "Docker-Client/19.03.13 (linux)"
    }


ADD get-docker.sh /get-docker.sh    重要操作,要在jenkins容器里面装一个docker客户端,因为jenkins要执行docker build,就是jenkins把代码拉取下来后,打包编译成jar包或者war包后,变成docker镜像,必然要使用docker命令。注,jenkins做成了image并运行在容器中,但并不代表容器能运行容器的命令。所以jenkins的容器要运行docker命令要不在容器里面安装一个docker服务,但jenkins容器里面安装docker引擎不建议,麻烦费时费力。有没有更简单的,有直接依赖宿主机的docker引擎,只要在jenkins容器里面装一个docker客户端,因为docker的客户端才能执行docker命令,通过能够和宿主机docker引擎通信进行操作。

echo "    StrictHostKeyChecking no" >> /etc/ssh/ssh_config && sh /get-docker.sh ; rm -f get-docker.sh    优化ssh ,ssh每次连接一台新的主机的时候,提示输入yes/no指纹验证,由于gitee是公网,每次拉取IP都不一样,所以不能每次都输入yes/no

2.2、做ssh密钥

[root@hdss7-200 ~]# ssh-keygen -t rsa -b 2048 -C "1151939762@qq.com" -N "" -f /root/.ssh/id_rsa
[root@hdss7-200 .ssh]# cat /root/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6n7YCHPECZzVk31gLP3sbuK3US4DMimYM9Bs/2G/VZFhXV8brEPMUK+VJOya4vz0tZyoz5NnJbg6ZJSzn4e5otqyP17py/3Hrx2uYonlCBc1cea6OTcX1FigGisHk1f7AZu507QJXwKDC6dLFmB0bKNjgVx8QKpQxfI5hK7SFwSzAU6WAHIDIXAcqf1FGg1mHwO9JaWjBLFz2+lNiWE645X0mNhjAMzgozu2n2d7KmlcuAsSJtstVTqzUqlwCBv5k2DIewYIHdadLiiUgdNEdzbDnxd3oCf3oWwUxiUToJgz3gsy4C0Q91ZIu4bmiSQNrUBjrd24tLLH4u6ngTy/V 1151939762@qq.com

拷贝私钥、config.json

[root@hdss7-200 .ssh]# cd /data/dockerfile/jenkins/
[root@hdss7-200 jenkins]# cp /root/.ssh/id_rsa ./
[root@hdss7-200 jenkins]# cp /root/.docker/config.json ./
[root@hdss7-200 jenkins]# ll
-rw-------. 1 root root  156 12月 26 11:21 config.json
-rw-r--r--. 1 root root  376 12月 26 10:31 Dockerfile
-rw-------. 1 root root 1675 12月 26 11:20 id_rsa
 

2.3、配置get-docker.sh

[root@hdss7-200 .ssh]# cd /data/dockerfile/jenkins/
[root@hdss7-200 jenkins]# wget -O get-docker.sh https://get.docker.com
[root@hdss7-200 jenkins]# chmod +x get-docker.sh
[root@hdss7-200 jenkins]# ll
-rw-------. 1 root root   156 12月 26 11:21 config.json
-rw-r--r--. 1 root root   376 12月 26 10:31 Dockerfile
-rwxr-xr-x. 1 root root 13857 12月  9 12:25 get-docker.sh
-rw-------. 1 root root  1675 12月 26 11:20 id_rsa

2.4、创建私有infra仓库

# 在harbor创建一个名字是infra的一个私有仓库,是infrastructure(基础设置)的缩写

2.5、制作Jenkins镜像

[root@hdss7-200 jenkins]# docker image build -t harbor.od.com:180/infra/jenkins:v2.190.3 ./

Sending build context to Docker daemon  20.48kB
Step 1/7 : FROM harbor.od.com:180/public/jenkins:v2.190.3
 ---> 22b8b9a84dbe
Step 2/7 : USER root
 ---> Running in c91da102040f
Removing intermediate container c91da102040f
 ---> 9982d5de38d9
Step 3/7 : RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
 ---> Running in 609b6609ac97
Removing intermediate container 609b6609ac97
 ---> 6e6ea342af35
Step 4/7 : ADD id_rsa /root/.ssh/id_rsa
 ---> 3a3f6325a9ae
Step 5/7 : ADD config.json /root/.docker/config.json
 ---> b7009a0f8917
Step 6/7 : ADD get-docker.sh /get-docker.sh
 ---> 4834c5785cfe
Step 7/7 : RUN echo "    StrictHostKeyChecking no" >> /etc/ssh/ssh_config && sh /get-docker.sh
 ---> Running in 29c0569072bf
# Executing docker install script, commit: 3d8fe77c2c46c5b7571f94b42793905e5b3e42e4
+ sh -c apt-get update -qq >/dev/null
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
debconf: delaying package configuration, since apt-utils is not installed
+ sh -c curl -fsSL "https://download.docker.com/linux/debian/gpg" | apt-key add -qq - >/dev/null
Warning: apt-key output should not be parsed (stdout is not a terminal)
+ sh -c echo "deb [arch=amd64] https://download.docker.com/linux/debian stretch stable" > /etc/apt/sources.list.d/docker.list
+ sh -c apt-get update -qq >/dev/null
+ [ -n  ]
+ sh -c apt-get install -y -qq --no-install-recommends docker-ce >/dev/null
debconf: delaying package configuration, since apt-utils is not installed
If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:

  sudo usermod -aG docker your-user

Remember that you will have to log out and back in for this to take effect!

WARNING: Adding a user to the "docker" group will grant the ability to run
         containers which can be used to obtain root privileges on the
         docker host.
         Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface
         for more information.
Removing intermediate container 29c0569072bf
 ---> 28da51376a1d
Successfully built 28da51376a1d
Successfully tagged harbor.od.com:180/infra/jenkins:v2.190.3

异常处理1:

使用build的时候,会将系统软件库更新到最新,这样是为了防止有的软件在库里找不到,由于使用的外国网站,所有会出现访问不了外国网站,导致build不成功

异常处理2:如果你发现 build异常的慢,而且有可能导致失败,可以指定使用阿里云,在get-docker.sh后加上--mirror=Aliyun
[root@hdss7-200 jenkins]# vim Dockerfile  # 最后一句修成这样

RUN echo "      StrictHostKeyChecking no" >> /etc/ssh/ssh_config && sh /get-docker.sh ; rm -f get-docker.sh --mirror=Aliyun 

异常处理3:build后报错如下

报错1:
DEPRECATION WARNING
    This Linux distribution (debian stretch) reached end-of-life and is no longer supported by this script.
    No updates or security fixes will be released for this distribution, and users are recommended
    to upgrade to a currently maintained version of debian.
Press Ctrl+C now to abort this script, or wait for the installation to continue.

解决:这个只不过是警告,可以不用理会,可能是get-docker.sh太新,而且内容太有些不支持,下载老版本的的get-docker.sh,可获取博主的资源



报错2:
: Unable to locate package docker-scan-plugin
The command '/bin/sh -c echo "  StrictHostKeyChecking no" >> /etc/ssh/ssh_config && sh /get-docker.sh' returned a non-zero code: 100

解决:他的意思是在docker中下载docker-scan-plugin异常,通过百度搜索
方案1:未解决
    1、apt-get update
    2、在安装包之前,如果命令位于dockerfile中,则需要添加-y(跳过系统提示,直接安装)
         apt-get -y install wget
    3、为了避免输出可以添加 -qq参数
         apt-get -qq -y install wget
如果细心的小伙伴会发现,其实在built中,有执行apt-get -qq update,所以应该不是这个导致,而且你在Docker中,加入apt-get update也不行
方案2:未解决
get-docker.sh使用百度云索引,上述中的get-docker.sh --mirror=Aliyun ,也不行
方案3:解决
思考,其实就是get-docker.sh报错,但是为什么下载不了docker-scan-plugin,还有一种可能,连
不上网,导致下载不了,而我在宿主机中测试,可以下载,如果通过docer run -ti 容器 /bin/bash
 进入容器后,发现,确实连不上网了,而这时候,我发现,容器ping宿主机IP无问题,可是宿主机
的网关、DNS都不通,这就是为什么不能下载docker-scan-plugi,为什么这样,最后是由于
daemon.json,没有加"bip": "172.7.21.1/24"。如何判断查看https://blog.csdn.net/Jerry00713/article/details/119427602

2.6、上传Jenkins镜像

[root@hdss7-200 jenkins]# docker login harbor.od.com:180
[root@hdss7-200 jenkins]# docker push harbor.od.com:180/infra/jenkins:v2.190.3

3、 验证容器连接gitee

jenkins镜像是否可以连接gitee

​​​​​​​[root@hdss7-200 jenkins]# docker run --rm harbor.od.com:180/infra/jenkins:v2.190.3 ssh -i /root/.ssh/id_rsa -T git@gitee.com
Warning: Identity file /root.ssh/id_rsa not accessible: No such file or directory.
Warning: Permanently added 'gitee.com,212.64.62.183' (ECDSA) to the list of known hosts.
Permission denied (publickey).    拒绝,公钥没有拷贝到gitee

[root@hdss7-200 jenkins]# cat /root/.ssh/id_rsa.pub    # 把数据拷贝到gitee

 

[root@hdss7-200 jenkins]# docker run --rm harbor.od.com:180/infra/jenkins:v2.190.3 ssh -i /root/.ssh/id_rsa -T git@gitee.com

其中 does not provide shell access意思就是你不需要输入yes/no

4、上传代码到gitee(如有项目可不做)

本文是把StanleyWang / dubbo-demo-service的资源上传自给的gitee Jerry00713 / dubbo-demo-service

[root@hdss7-200 ~]# yum install -y git
[root@hdss7-200 ~]# git clone git@gitee.com:stanleywang/dubbo-demo-service.git
[root@hdss7-200 ~]# cd dubbo-demo-service/
[root@hdss7-200 dubbo-demo-service]# git config --global user.email "1151939762@qq.com"
[root@hdss7-200 dubbo-demo-service]# git config --global user.name "Jerry00713 "
[root@hdss7-200 dubbo-demo-service]# git remote add dubbo git@gitee.com:jerry00713/dubbo-demo-service.git
[root@hdss7-200 dubbo-demo-service]# git push -u dubbo master

5、配置资源应用于容器

5.1、创建/声明infra名称空间

 在hdss7-21或者hdss7-22 操作

创建一个infra名称空间,因为jenkins也需要放到k8s单独的名称空间,让这个名称空间只运行运维相关的基础设施服务

[root@hdss7-21 ~]# kubectl create ns infra
namespace/infra created

infra命名空间下的pod想从harbor私有仓库拉取镜像,根本拉取不到镜像。需要在infra命名空间创建一个secret资源,把登录harbor.od.com:180用到的管理员账户、密码需要声明出来,pod拉取镜像的时候会带secret资源进行请求。

任意一个运算节点 (如hsdd7-21),在infra命名空间创建一个secret资源,类型是docker-registry 。名字叫harbor,后面参数

[root@hdss7-21 ~]# kubectl create secret docker-registry harbor --docker-server=harbor.od.com:180 --docker-username=admin --docker-password=Harbor12345 -n infra

查看secret(不参与部署):

1、查看infra命名空间下有多少个secret资源

例如新建一个harbor1的secret资源,查看infra命名空间下的所有secret资源
  
[root@7-21 ~]# kubectl get secret -n infra
NAME                  TYPE                                  DATA   AGE
default-token-vj94t   kubernetes.io/service-account-token   3      16m
harbor                kubernetes.io/dockerconfigjson        1      16m

[root@7-21 ~]# kubectl create secret docker-registry harbor1 --docker-server=harbor.od.com:180 --docker-username=admin --docker-password=Harbor12345 -n infra
secret/harbor1 created

[root@7-21 ~]# kubectl get secret -n infra
NAME                  TYPE                                  DATA   AGE
default-token-vj94t   kubernetes.io/service-account-token   3      16m
harbor                kubernetes.io/dockerconfigjson        1      16m
harbor1               kubernetes.io/dockerconfigjson        1      5s

2、查看infra命名空间下名字叫harbor的secret资源

[root@7-21 ~]# kubectl get secret harbor -o yaml -n infra
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJoYXJib3Iub2QuY29tOjE4MCI6eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJIYXJib3IxMjM0NSIsImF1dGgiOiJZV1J0YVc0NlNHRnlZbTl5TVRJek5EVT0ifX19
kind: Secret
metadata:
  creationTimestamp: "2021-12-05T11:31:13Z"
  name: harbor
  namespace: infra
  resourceVersion: "35037"
  selfLink: /api/v1/namespaces/infra/secrets/harbor
  uid: ec6de3ac-a5f0-4a86-b136-1cfb561fe6a1
type: kubernetes.io/dockerconfigjson

注:data后面为(名字叫harbor的secret资源)的账户密码

3、解密(名字叫harbor的secret资源)的账户密码

格式:echo "data中的内容" | base64 --decode

[root@7-21 ~]# echo "eyJhdXRocyI6eyJoYXJib3Iub2QuY29tOjE4MCI6eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJIYXJib3IxMjM0NSIsImF1dGgiOiJZV1J0YVc0NlNHRnlZbTl5TVRJek5EVT0ifX19" | base64 --decode
{"auths":{"harbor.od.com:180":{"username":"admin","password":"Harbor12345","auth":"YWRtaW46SGFyYm9yMTIzNDU="}}}[root@7-21 ~]#

4、删除不需要的secret资源

[root@7-21 ~]# kubectl delete secret harbor1 -n infra
secret "harbor1" deleted
[root@7-21 ~]# kubectl get secret -o wide -n infra
NAME                  TYPE                                  DATA   AGE
default-token-vj94t   kubernetes.io/service-account-token   3      26m
harbor                kubernetes.io/dockerconfigjson        1      25m

如果删除后,会立即以相似的名称进行重建(即使使用 --force)

5.2、创建共享存储

让jenkins的 pod实现持久化数据的共享存储,即使pod宕机,重启一个pod后,数据使用的是共享存储,所以数据不会丢失。注意:要想实现多pod数据实时一致性(比如数据库做双活,A的pod落盘的数据,B的pod要及时更新,相反B的pod落盘,A的pod也要及时更新。比如修改网页的index页面,不用每一个pod都修改)。所以这些pod要把持久化路径挂在一个位置,防止多个pod同时插入数据会乱套。当然jenkins是有状态服务,我们一般会启动一个pod,不会存在多pod,但假设规划pod落盘到7-21的本地目录,如果pod异常了,重启pod后挂载到22节点上呢,以前的数据就没了。还有一种方案,给所有的pod打污点,只有7-21的能容忍,只能调度到7-21的节点,但是不是害的考虑7-21节点的负载情况,jenkins是java项目吃资源,所以那还不如做共享存储目录简单,而且数据还能得到保障。NFS共享存储放在 hdss7-200 上,用于存储Jenkins持久化文件。所有Node节点和hdss7-200都需要安装NFS,通过NFS间接让Node节点的数据存放在中hdss7-200的共享存储目录,挂在hdss7-200的指定NFS

在hdss7-21、hdss7-22、hdss7-200 都需要操作
[root@hdss7-21 ~]# yum install -y nfs-utils
[root@hdss7-22 ~]# yum install -y nfs-utils
[root@hdss7-200 ~]# yum install -y nfs-utils

在hdss7-200操作,共享存储在hdss7-200 上,所有节点需要挂在hdss7-200存储端

[root@hdss7-200 ~]# mkdir /data/nfs-volume
[root@hdss7-200 ~]# vim /etc/exports

/data/nfs-volume  10.4.7.0/24(rw,sync,no_root_squash)

解释:
把/data/nfs-volume目录共享给10.4.7.0/24
参数rw :可读可以写
参数no_root_squash:登入 NFS 主机使用分享目录的使用者,如果是 root 的话,那么对于这个分享的目录来说,他就具有 root 的权限,单词squash是压缩压扁的意思,这种配置不建议使用不安全。
参数root_squash:在登入 NFS 主机使用分享之目录的使用者如果是 root 时,那么这个使用者的权限将被压缩成为匿名使用者,通常他的 UID 与 GID 都会变成 nobody 那个系统账号的身份;

在hdss7-21、hdss7-22、hdss7-200 都需要操作
[root@hdss7-200 jenkins]# systemctl start nfs;systemctl enable nfs
[root@hdss7-21 jenkins]# systemctl start nfs;systemctl enable nfs
[root@hdss7-22 jenkins]# systemctl start nfs;systemctl enable nfs

共享存储怎么应用:使用资源配置清单应用共享存储

5.3、 配置资源配置清单

在hdss7-200 操作

[root@hdss7-200 k8s-yaml]# mkdir -p /data/k8s-yaml/jenkins
[root@hdss7-200 k8s-yaml]# cd /data/k8s-yaml/jenkins/
[root@hdss7-200 jenkins]# vi deployment.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: jenkins
  namespace: infra
  labels: 
    name: jenkins
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: jenkins
  template:
    metadata:
      labels: 
        app: jenkins 
        name: jenkins
    spec:
      volumes:
      - name: data
        nfs: 
          server: hdss7-200
          path: /data/nfs-volume/jenkins_home
      - name: docker
        hostPath: 
          path: /run/docker.sock
          type: ''
      containers:
      - name: jenkins
        image: harbor.od.com:180/infra/jenkins:v2.190.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          protocol: TCP
        env:
        - name: JAVA_OPTS
          value: -Xmx512m -Xms512m
        volumeMounts:
        - name: data
          mountPath: /var/jenkins_home
        - name: docker
          mountPath: /run/docker.sock
      imagePullSecrets:
      - name: harbor
      securityContext: 
        runAsUser: 0
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600

解释:

kind: Deployment    # pod控制器主要两种类型:daemonset每一个运算节点启动一个, Deployment 根据设置可以启动随意几个
apiVersion: extensions/v1beta1  # 指定资源连接那个版本的apiserver,,此值必须在kubectl api-versions中 
metadata:   # 配置资源的元数据/属性
  name: jenkins   #  Deployment 资源的名字,在同一个namespace中必须唯一
  namespace: infra    # 部署在哪个名命空间中,不写的话默认创建在default空间
  labels:    # 自定义标签
    name: jenkins #自定义标签名字
spec:  # 资源规范字段
  replicas: 1         # 声明副本数目,根据设置pod只是启动1个
  selector:           # 定义选择器​​​​​​​
    matchLabels:    # 标签选择器,匹配标签,定义如下配置的pod应该连接那个pod控制器
      name: jenkins # 选择连接名字是jenkins的pod控制器资源
  template:         # pod模板
    metadata:  # 配置资源的元数据/属性
      labels:  # 自定义pod标签
        app: jenkins   # 标签的名字
        name: jenkins  # 给dp跟pod进行关联的信息定义一个名字
    spec:  # 资源规范字段
      volumes:  # 定义挂载
      - name: data   # 定义挂载卷的名字,k8s处处是资源,起名字后才能在k8s中找到
        nfs:         # 定义使用的卷类型, k8s支持nfs驱动。若遇到不支持的存储卷,假设不支持nfs,可以使用pvc,使用它间
                       接支持其他类型的分部式存储,声明pvc,用pvc在声明nfs存储,在pod中挂载pvc.
          server: hdss7-200   # nfs服务器在哪
          path: /data/nfs-volume/jenkins_home    # 去nfs服务器找到path目录,并共享路径
      - name: docker   # 定义挂载卷的名字
        hostPath:      # 挂载类型是本机,把本机的某一个文件挂载到docker中。scheduler决定pod在那个节点启动,就调用那个本地文件
          path: /run/docker.sock   # 把本机这个文件共享,docker客户端就可以跟宿主机的docker服务端进行通信
          type: ''
      containers:      # 定义容器内部的操作
      - name: jenkins  # 容器名字
        image: harbor.od.com/infra/jenkins:v2.190.3   # 使用镜像
        imagePullPolicy: IfNotPresent # 镜像拉取的策略,默认分为三种:1、always无论本地是不是有这个镜像,都要从从私有harbor镜像仓库中拉取
                                        镜像,2、never 无论如何都不去远程仓库拉取镜像,都是用本地的。3、IfNot如果本地没有,就去harbor镜像仓库拉取镜像,
        ports:         # 定义端口
        - containerPort: 8080  # 容器开发对外的端口,jenkin启动后监听8080端口,把容器内部的8080端口映射到容器外部,也就是docker -P 8080:8080
          protocol: TCP   # 协议
        env:              # 容器运行前,需给容器内部设置或者说是增加环境变量,跟docker -e 一样环境变量
        - name: JAVA_OPTS  # 给定义此环境变量起名字
          value: -Xmx512m -Xms512m   # 定义环境变量,JAVA_OPTS=-Xmx512m -Xms512m,设置最大的堆内存是512,jenkins比较吃资源
        volumeMounts:     # 定义挂在路径,搭配上述配置volumes使用
        - name: data      # 使用上述定义volumes,名字是data挂载卷
          mountPath: /var/jenkins_home  # 决定上述data挂载卷,宿主机的/data/nfs-volume/jenkins_home 挂载容器的哪个地方
        - name: docker    # 使用上述定义volumes,名字是docker挂载卷
          mountPath: /run/docker.sock   # 决定上述docker挂载卷,宿主机的/run/docker.sock挂载容器的哪个地方
      imagePullSecrets:   # delpoyment另外的一个重要参数,刚才在infra命名空间创建一个harbor的secret资源,当从harbor私有仓库拉取镜像时必须加上,否则拉不到
      - name: harbor      # 这里声明使用名字是harbor的secret资源类型是docker-registry (secret docker-registry harbor)
      securityContext:    # 说明要使用哪个账户启动这个容器
        runAsUser: 0      # 使用root账户启动这个容器, 0指root用户的uid。
  strategy:       # 定义策略
    type: RollingUpdate     # 采用滚动更新的方法,升级jenkins,
    rollingUpdate:          # 定义滚动更新方法
      maxUnavailable: 1     # 在更新过程中能够进入不可用状态的Pod的最大值,可以为百分比,也可以为整数,比如maxUnavailable: 30%意思是假如此
                              pod一共启动10份,在更新pod控制器后,10份pod不会同时delete,在创建,而是保证10*30%=3台,始终最大只有3台在更新
                              pod,等某一个pod更新完成后在继续更新其他的pod。如果是maxUnavailable: 1,整数意思是,每次保证1台更新,不能再多了
      maxSurge: 0           # 表示滚动升级时会先启动0个pod
  revisionHistoryLimit: 7   # 保留几份更新记录pod 7份提供回滚使用
  progressDeadlineSeconds: 600   # 启动容器后,多长时间一直没有RUNING判断为失败,失败就会重新启动容器,jenkins比较吃资源,所以不要给太少

什么是滚动更新:
滚动更新是一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新。
滚动更新的最大的好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性。

如何通过maxUnavailable、maxSurge正确理解滚动更新时候pod会启动多少份
方法是升级期间pod的范围:replicas副本集 - maxUnavailable ~  replicas副本集 + maxSurge
什么意思:就是滚动更新时候maxSurge按照预定会先启动几个pod,所以当前pod数量在replicas副本集 + maxSurge ,而maxUnavailable会保证有几个或者%多少
          在更新过程中,也就是replicas副本集 - maxUnavailable

其中:
1. maxUnavailable: [0%, 100%] 向下取整,比如10个副本,5%的话==0.5个,但计算按照0个;
2. maxSurge: [0%, 100%] 向上取整,比如10个副本,5%的话==0.5个,但计算按照1个;		  
		  	  
比如:
maxSurge: 1 表示滚动升级时会先启动1个pod
maxUnavailable: 1 表示滚动升级时允许的最大Unavailable的pod个数
由于replicas为3,则整个升级,pod个数在3-1 ~ 3+1个之间

比如:
maxSurge: 1 表示滚动升级时会先启动1个pod
maxUnavailable: 50% 表示滚动升级时允许的最大Unavailable的pod个数
由于replicas为3,则整个升级,pod个数在3*50% ~ 3+1个之间,也就是3*50%=1.5,maxUnavailable向下取整,就是1,所以1~4个之间

滚动更新:https://blog.csdn.net/Jerry00713/article/details/123791842

[root@hdss7-200 jenkins]# vi service.yaml

kind: Service
apiVersion: v1
metadata: 
  name: jenkins
  namespace: infra
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  selector:
    app: jenkins

 解释:

port: 80   监听在ClusterIP(虚拟的集群网络)的80端口,相当于把容器里面的8080端口映射到集群网络的80端口,定义多少端口都无所谓,但是ingress中监听的是这个端口
targetPort: 8080   容器里面跑的8080端口,dp中配置把容器的8080端口映射出来,然后service再把容器的8080端口映射到集群网络80端口

[root@hdss7-200 jenkins]# vi ingress.yaml

kind: Ingress
apiVersion: extensions/v1beta1
metadata: 
  name: jenkins
  namespace: infra
spec:
  rules:
  - host: jenkins.od.com
    http:
      paths:
      - path: /
        backend: 
          serviceName: jenkins
          servicePort: 80

解释:
servicePort: 80     这里面的80端口必须跟service.yaml中的port: 80一致,因为ingress中监听的是service的ClusterIP

[root@hdss7-200 jenkins]# mkdir -p /data/nfs-volume/jenkins_home

启动jenkins,在hdss7-21或者hdss7-22操作

[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/jenkins/deployment.yaml
deployment.extensions/jenkins created
[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/jenkins/service.yaml
service/jenkins created
[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/jenkins/ingress.yaml
ingress.extensions/jenkins created
[root@hdss7-21 ~]# kubectl get pods -n infra        jenkins很耗费资源,启动的很慢
NAME                       READY  STATUS             RESTARTS   AGE
jenkins-64ff665996-6kl92   0/1    ContainerCreating  0          4m54s

[root@hdss7-21 ~]# kubectl logs jenkins-64ff665996-6kl92 -n infra
Error from server (BadRequest): container "jenkins" in pod "jenkins-64ff665996-6kl92" is waiting to start: ContainerCreating

[root@hdss7-21 ~]# kubectl get pods -n infra
NAME                       READY   STATUS    RESTARTS   AGE
jenkins-64ff665996-6kl92   1/1     Running   0          5m27s

[root@hdss7-21 ~]# kubectl logs jenkins-64ff665996-6kl92 -n infra

Running from: /usr/share/jenkins/jenkins.war
webroot: EnvVars.masterEnvVars.get("JENKINS_HOME")
2020-12-27 01:23:47.387+0000 [id=1]    INFO    org.eclipse.jetty.util.log.Log#initialized: Logging initialized @14171ms to org.eclipse.jetty.util.log.JavaUtilLog
2020-12-27 01:23:51.161+0000 [id=1]    INFO    winstone.Logger#logInternal: Beginning extraction from war file

如何判断jenkins完全启动:查看jenkins pod日志,里面有Jenkins is fully up and running说明完全启动,其中jenkins 容器后面的458.086是占用的内存(字节),一个字节=8位

[root@hdss7-21 ~]# kubectl logs jenkins-64ff665996-6kl92 -n infra |egrep "Jenkins is fully up and running"
2020-12-27 09:29:27.355+0000 [id=19]    INFO    hudson.WebAppMain$3#run: Jenkins is fully up and running

查看hdss-7-200的挂载目录:

[root@hdss7-200 jenkins]# ll /data/nfs-volume/jenkins_home
total 36
-rw-r--r--.  1 root root 1643 Mar 28 13:42 config.xml
-rw-r--r--.  1 root root   50 Mar 28 13:41 copy_reference_file.log
-rw-r--r--.  1 root root  156 Mar 28 13:41 hudson.model.UpdateCenter.xml
-rw-------.  1 root root 1712 Mar 28 13:41 identity.key.enc
-rw-r--r--.  1 root root    7 Mar 28 13:41 jenkins.install.UpgradeWizard.state
-rw-r--r--.  1 root root  171 Mar 28 13:41 jenkins.telemetry.Correlator.xml
drwxr-xr-x.  2 root root    6 Mar 28 13:41 jobs
drwxr-xr-x.  3 root root   19 Mar 28 13:41 logs
-rw-r--r--.  1 root root  907 Mar 28 13:41 nodeMonitors.xml
drwxr-xr-x.  2 root root    6 Mar 28 13:41 nodes
drwxr-xr-x.  2 root root    6 Mar 28 13:41 plugins
-rw-r--r--.  1 root root   64 Mar 28 13:41 secret.key
-rw-r--r--.  1 root root    0 Mar 28 13:41 secret.key.not-so-secret
drwx------.  4 root root  265 Mar 28 13:41 secrets
drwxr-xr-x.  2 root root   67 Mar 28 13:42 updates
drwxr-xr-x.  2 root root   24 Mar 28 13:41 userContent
drwxr-xr-x.  3 root root   54 Mar 28 13:41 users
drwxr-xr-x. 11 root root 4096 Mar 28 13:41 war
[root@hdss7-200 jenkins_home]# 

5.4、验证容器是否按照dockerfile执行

1、先确保jenkins启动

[root@hdss7-22 src]# docker ps -a |grep jenkins

3a51d305f3b1        28da51376a1d                            "/sbin/tini -- /usr/…"   12 hours ago        Up 12 hours                                      k8s_jenkins_jenkins-64ff665996-dc8bh_infra_1a1c60e8-ddd7-4a90-b891-0338332f85a2_1
6d82e077333c        harbor.od.com:180/public/pause:latest   "/pause"                 12 hours ago        Up 12 hours                                      k8s_POD_jenkins-64ff665996-dc8bh_infra_1a1c60e8-ddd7-4a90-b891-0338332f85a2_1
2bdd4b0db627        harbor.od.com:180/infra/jenkins         "/sbin/tini -- /usr/…"   19 hours ago        Exited (255) 12 hours ago                        k8s_jenkins_jenkins-64ff665996-dc8bh_infra_1a1c60e8-ddd7-4a90-b891-0338332f85a2_0
74ef8024f5c6        harbor.od.com:180/public/pause:latest   "/pause"                 19 hours ago        Exited (255) 12 hours ago                        k8s_POD_jenkins-64ff665996-dc8bh_infra_1a1c60e8-ddd7-4a90-b891-0338332f85a2_0

2、进入jenkins 的docker容器,要不就用命令,要不用dashboard

命令( docker exec -ti 名字  /bin/bash )

root@jenkins-64ff665996-dc8bh:/# whoami    说明我的用户是root
root
root@jenkins-64ff665996-dc8bh:/# date      说明我的时间是东八区
Mon Dec 28 05:33:38 CST 2020

root@jenkins-64ff665996-dc8bh:/# docker ps -a   在容器内, ps -a查看正在运行的容器,然后跟此容器的宿主机docker ps -a查看正在运行的容器是否一致,如果一致,就说明是容器使用的是宿主机的/run/docker.sock
CONTAINER ID        IMAGE                                   COMMAND                  CREATED             STATUS                      PORTS                NAMES
b1628ebcefc3        add5fac61ae5                            "/entrypoint.sh --ap…"   12 hours ago        Up 12 hours                                      k8s_traefik-ingress_traefik-ingress-t27lb_kube-system_dba425b1-328d-4960-bad5-
等等
[root@hdss7-22 src]# docker ps -a 
b1628ebcefc3        add5fac61ae5                            "/entrypoint.sh --ap…"   12 hours ago        Up 12 hours                                      k8s_traefik-ingress_traefik-ingress-t27lb_kube-system_dba425b1-328d-4960-bad5-
等等

root@jenkins-64ff665996-dc8bh:/# docker login harbor.od.com:180   不用输入账户密码直接登录harbor.od.com:180 ,说明已经使用宿主机/root/.docker/config.json
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
root@jenkins-64ff665996-dc8bh:/# cat /root/.docker/config.json 
{
        "auths": {
                "harbor.od.com:180": {
                        "auth": "YWRtaW46SGFyYm9yMTIzNDU="
                }
        },
        "HttpHeaders": {
                "User-Agent": "Docker-Client/19.03.14 (linux)"
        }
}

root@jenkins-64ff665996-dc8bh:/# ssh -i /root/.ssh/id_rsa -T git@gitee.com     -T测试连接, 指定使用git用户去测试连接gitee.com仓库
Warning: Permanently added 'gitee.com,212.64.62.183' (ECDSA) to the list of known hosts.
Hi Jerry00713 (DeployKey)! You've successfully authenticated, but GITEE.COM does not provide shell access.
Note: Perhaps the current use is DeployKey.
这是一个DeployKey部署公钥,比已经成功被认证,但是gitee.com并不能提供shell接入点,你这是一个部署公钥

异常问题处理:

到检查docker ps -a,发现没有docker,发现jenkins包在harbor中大约在200M左右,在ben'didocker image约在500M左右,此时就是之前构建Dockerfile jenkins问题,docker没有封装进去(此问题对应的上述built报错),具体解决方案看上文,如果在上文中built报错,没有安装docker,而且你已经创建了jenkins的资源,容器已经启动了,这个时候,正确的操作流程为:jenkins缩容为0,删除hdss7-21或者hdss7-22本地的jenkins镜像,删除harbor的jenkins镜像,重新构建jenkins,成功后,推送到harbor,在扩容jenkins缩容为1。为什么解决问题后,重新built,重新提交到barbor中,直接删除已经存在的jenkins容器,deployment会重新拉去一个新的,不就解决了么。因为 deployment.yaml 中的 imagePullPolicy: IfNotPresent 如果本地没有,就去harbor镜像仓库拉取镜像,现在本地已经有了,所以不会在harbor拉

1、停止jenkins容器,做法是,jenkins缩容为0,如果不停止,jenkins的docker启动,hdss7-21或者hdss7-22本地的jenkins镜像删除不掉。

kubectl scale deployment jenkins --replicas=0 -n infra   # 缩容为0,或者使用dashboard 缩容为0
kubectl get pods -n infra      # 过一阵子查看是不是容器消亡
docker image ls -a |grep jenkins    # 查看封装的infra的 jenkins镜像的nameid是什么
docker rmi 4c71fe1b453e    #  删除本地镜像,由于jenkins是启动一份,所以这个不在hdss7-21就在hdss7-22

2、删除harbor的jenkins镜像

3、找到built报错原因,冲重新bulit

4、提交到harbor

5、kubectl scale deployment jenkins --replicas=1 -n infra   # 扩容为1,或者使用dashboard 缩容为1

5.5、 配置jenkins.od.com域名

在hdss7-11操作

[root@hdss7-11 ~]# vi /var/named/od.com.zone 

$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2020010506 ; serial
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
$TTL 60 ; 1 minute
dns                A    10.4.7.11
harbor             A    10.4.7.200
k8s-yaml           A    10.4.7.200
traefik            A    10.4.7.10
dashboard          A    10.4.7.10
zk1                A    10.4.7.11
zk2                A    10.4.7.12
zk3                A    10.4.7.21
jenkins            A    10.4.7.10

[root@hdss7-11 ~]# systemctl restart named
[root@hdss7-11 ~]# dig -t A jenkins.od.com @10.4.7.11 +short
10.4.7.10

5.6、 访问jenkins.od.com

方式一:通过直接访问jenkins.od.com(正常访问)

方式二:直接绕过dns解析,直接访问容器的IP+端口,但注意需要配置路由,否则无法访问k8s内部资源

[root@hdss7-21 ~]# kubectl get pods -o wide -n infra               
NAME                       READY   STATUS    RESTARTS   AGE    IP           NODE                NOMINATED NODE   READINESS GATES
jenkins-64ff665996-dc8bh   1/1     Running   0          2m4s   172.7.22.4   hdss7-22.host.com   <none>           <none>

这里发现jenkins容器飘逸22机器上IP:172.7.22.4,目前只有hdss7-21、hdss7-22才能直接跟172.7.22.0/24通信,hdss7-21也能通信原因取决于flanned,gw模式,原理就是写了个路由,所在win机器上做指向172.7.22.0/24网络的静态路由,不就行了

route add 172.7.22.0 mask 255.255.255.0 10.4.7.22 if 14 -p
route add 172.7.21.0 mask 255.255.255.0 10.4.7.21 if 14 -p

解释:添加二条路由记录,所有到172.7.21.0/24、172.7.22.0/24网段的数据包,都把数据给到网关10.4.7.21、10.4.7.22。而win机器能跟10.4.7.21、10.4.7.22通信的是虚拟网卡vmnat8,if  14就是vmnat8的网卡接口,-p 是永久路由。

如何查看虚拟机vmnat8 的网卡编号,route print 命令显示出来的第一组数据“接口列表”,就是网卡编号

6、 登录配置jenkins

1、访问jenkins.od.com后的地一步输入登录密码

[root@hdss7-200 jenkins_home]# cat /data/nfs-volume/jenkins_home/secrets/initialAdminPassword      # 查看密码登录
a6e44f314783424ebefd270d7d26a8c1

2、输入密码并登录后,跳转如下界面,点击右上角× 跳过,因为所有的插件可以安装完成后在去做


3、如果跳转如下界面,必须输入此账户密码,因为后续Spinnaker与jenkins连接时候用 

image.png

4、开始使用jenkis

注:如果点击第2步后,直接跳到第4步,没有输入密码直接进入后,需要更改密码

密码:admin123

重新登录账户:admin  密码:admin123 

6.1、配置安全策略

调整两个安全选项 Manage Jenkins → Configure Global Security

Allow anonymous read access    允许匿名用户能访问,但是不能配置
Prevent Cross Site Request Forgery exploits  (默认打√开启阻止跨域请求)。需要取消它,使其开启不阻止跨域请求,因为后期会用到Spinnaker跨域请求jenkins流水线配置

6.2、配置插件加速地址

  1、到(Manage Jenkins →Manage Plugins)中装流水线有关的Plugins,叫蓝海

 2、按照如下,下载Blue Ocean

Blue Ocean的好处:CI/CD pipeline可视化界面、pipeline编辑器(手动傻瓜式操作)、能快速精准的定位到错误 

3、都下载完成之后,在界面最下,有一个类似Restart after installation 安装完成重启,点击后重启jenkins

注:如果蓝海下载卡,或者失败,可能是使用国外源不行,配置国内下载源:

地址:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

# 修改下载地址
[root@hdss7-200 ~]# cd /data/nfs-volume/jenkins_home/updates
[root@hdss7-200 updates]# sed -i 's#http://updates.jenkins-ci.org/download#https://mirrors.tuna.tsinghua.edu.cn/jenkins#g;s#http://www.google.com#https://www.baidu.com#g' default.json

很重要:

如果安装Blue Ocean提示拒绝加载此版本Blue Ocean,那就是此版本不在被支持,需要下载最新的jenkins 

k8s--Jenkins拒绝加载此版本Blue Ocean、k8s--Jenkins_Jerry00713的博客-CSDN博客

Spinnaker调用Jenkins API 返回403错误_Jerry00713的博客-CSDN博客

6.3、Jenkins 忘记admin密码拯救方法

安装jenkins的目录有一个users的文件夹,每一个用户对应着一个用户名命名的文件夹。打开admin文件夹,里面有一个config.xml文件,就是admin用户的一些配置信息

[root@hdss7-200 ]# cd /data/nfs-volume/jenkins_home/users/admin_34029020338654908
[root@hdss7-200 admin_34029020338654908]# cat config.xml |grep password
 <passwordHash>#jbcrypt:$2a$10$MiIVR0rr/UhQBqT.bBq0QehTiQVqgNpUGyWW2nJObaVAM/2xSQdSq</passwordHash>

红色的就为密码,只不过是被加密后的,所以一旦忘记密码,把对应的用户的config.xml里面的密码改成:

#jbcrypt:$2a$10$MiIVR0rr/UhQBqT.bBq0QehTiQVqgNpUGyWW2nJObaVAM/2xSQdSq

解密后:123456,随后在重启jenkins

7、安装Maven到Jenkins

7.1 、下载Maven二进制包

Maven是把代码编成译jar包或者war包的java程序,所以Jenkins需要使用Maven把代码进行打包,直接将Maven的二进制包拷贝到Jenkins持久化目录中,让Jenkins自己去调用。
apache基金会,官网:Maven – Welcome to Apache Maven
Maven各个版本: Maven – Maven Releases History
其中大版本Maven 3.1+、Maven 3.0.x、Maven 2、Maven 1  等。如果jdk跟Maven版本差异不匹配,会导致编译不过去。而目前大部分java应用都在jdk1.7以上,所以大部分程序用到都是Maven 3。

[root@hdss7-22 ~]# kubectl exec jenkins-64ff665996-dc8bh -n infra -- java -version   查看jenkins 容器 java版本
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)

注意:直接进入Jenkins容器里执行java -version后,会显示java版本,说明这个Jenkins容器已经安装了jdk。这个jdk是我们dockerfile安装的还是Jenkins镜像自带的呢?

通过检查了配置、共享目录,没发现有由我们操作安装jdk,由于当前使用的jenkins镜像是基于网上的jenkins镜像改吧改吧后的结果,所以验证官方的jenkins镜像是否有无jdk,有就说明是自带的

[root@hdss7-200 jdk_versions]# docker image ls |grep jenkins/jenkins
jenkins/jenkins                                                      2.190.3                         22b8b9a84dbe        13 months ago       568MB
[root@hdss7-200 jdk_versions]# docker run -it 22b8b9a84dbe /bin/bash    # 验证了jdk是pull 镜像自带的
jenkins@53fd0590a043:/$ java -version     
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)

由于使用的是jdk 1.8.0_232,教程使用3.6.1,也可以使用最新Maven版本3.6.3

 点击最下面的archives,已经归档的

https://archive.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz   二进制包

7.2 、安装二进制包

在 hdss7-200 操作

通过kubectl exec jenkins-64ff665996-dc8bh -n infra -- java -version  查看jenkins容器jdk版本是openjdk version "1.8.0_232",所以我们使用maven-3.6.1-8u232作为 jdk1.8.0_232的maven

[root@hdss7-200 jenkins_home]# cd /opt/src/
[root@hdss7-200 src]# wget https://archive.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz
[root@hdss7-200 src]# mkdir -p /data/nfs-volume/jenkins_home/maven-3.6.1-8u232
[root@hdss7-200 src]# tar -xf apache-maven-3.6.1-bin.tar.gz -C /data/nfs-volume/jenkins_home/
[root@hdss7-200 src]# cd /data/nfs-volume/jenkins_home/
[root@hdss7-200 jenkins_home]# ll |grep apache-maven-3.6.1
drwxr-xr-x.  6 root root   99 12月 28 06:33 apache-maven-3.6.1

[root@hdss7-200 jenkins_home]# mv apache-maven-3.6.1/* maven-3.6.1-8u232/
[root@hdss7-200 apache-maven-3.6.1]# cd /data/nfs-volume/jenkins_home/maven-3.6.1-8u232/

[root@hdss7-200 maven-3.6.1-8u232]# ll
drwxr-xr-x. 2 root root     97 12月 28 06:33 bin
drwxr-xr-x. 2 root root     42 12月 28 06:33 boot
drwxr-xr-x. 3  501 games    63 4月   5 2019  conf
drwxr-xr-x. 4  501 games  4096 12月 28 06:33 lib
-rw-r--r--. 1  501 games 13437 4月   5 2019  LICENSE
-rw-r--r--. 1  501 games   182 4月   5 2019  NOTICE
-rw-r--r--. 1  501 games  2533 4月   5 2019  README.txt

7.3、对maven初始化配置

7.3.1、设置国内的镜像源

# 配置maven的xml文件,拉取java包从阿里云拉取,不要从国外拉取

[root@hdss7-200 maven-3.6.1-8u232]# vim /data/nfs-volume/jenkins_home/maven-3.6.1-8u232/conf/settings.xml

<mirror>
  <id>nexus-aliyun</id>
  <mirrorOf>*</mirrorOf>
  <name>Nexus aliyun</name>
  <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

按照如下更改

最后

此过程不涉及本次实验,不需要配置,了解即可

7.3.2、maven配置不同jdk
需求:公司项目基于maven3才能编译,而maven3必须要用jdk 1.7其他版本无法运行。
过程:在共享目录中添加1.7的jdk,让maven3指定这个1.7的jdk。
下载jdk-7u80-linux-x64.tar.gz:
Java Archive Downloads - Java SE 7

部署:
[root@hdss7-200 src]# cd /opt/src
[root@hdss7-200 src]# rz jdk-7u80-linux-x64.tar.gz
[root@hdss7-200 src]# tar -xf jdk-7u80-linux-x64.tar.gz -C /data/nfs-volume/jenkins_home
[root@hdss7-200 src]# cd /data/nfs-volume/jenkins_home
[root@hdss7-200 jenkins_home]# ll |grep jdk1.7.0_80
drwxr-xr-x.  8   10  143  233 4月  11 2015 jdk1.7.0_80
[root@hdss7-200 jenkins_home]# cd maven-3.6.1-8u232/bin/
[root@hdss7-200 bin]# file mvn
mvn: POSIX shell script, ASCII text executable

[root@hdss7-200 bin]# vi mvn       # 在mvn最开头处添加一条,就可以实现maven-3.6.1-8u232使用jdk1.7.0_80。注意:使用jenkins中绝对路径
JAVA_HOME='/var/jenkins_home/jdk1.7.0_80'

这里注意:meaven启动会按照mvn这个脚本启动,当mvn脚本中没有声明JAVA_HOME是什么,mvn作为一个脚本,调用JAVA_HOME必然是从环境变量中获取。所以默认情况,mvn使用的是环境变量中配置的jdk。但是在脚本的一开头,直接定义JAVA_HOME=/var/jenkins_home/jdk1.7.0_80目录,脚本就会从此目录中获取jdk。而此目录我们通过共享目录挂载到容器

7.3.2、如果meaven使用了不对应的jdk,在运行编译结构化参数jenkins后就会有如下报错:

例子:我的项目只能运行在maven-3.6.1-8u232,对应的jdk要用到1.8.0_232。当pull下载的jenkins:2.190.3的时候,此版本自带的jdk是1.8.0_232,按照此版本制作我的项目完全无问题,奈何此版本在2019年的时候,jenkins中可以支持安装Blue Ocean,但是在2021年的时候Jenkins拒绝为此版本加载Blue Ocean。所以我更新了jenkins为Jenkins 2.319.1。此版本的jdk是openjdk version "11.0.13" 2021-10-19,若用此jenkins制作java的项目,jenkins使用maven-3.6.1-8u232版本的构建项目,mvn默认使用$JAVA_HOME是获取的环境变量,就会获取jdk 11.0.13,导致maven不能跟jdk匹配成功,报如下错误。

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project dubbo-api: Compilation failure: Compilation failure: 
[ERROR] Source option 5 is no longer supported. Use 6 or later.
[ERROR] Target option 1.5 is no longer supported. Use 1.6 or later.
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

解决方案:就是需要使用jdk1.8.0_232,操作如下(由于本人未找到jdk1.8.0_231),但是差别不大,所以使用了jdk1.8.0_231

[root@hdss7-21 ~]# cd /opt/src
[root@hdss7-21 ~]# rz jdk-8u231-linux-x64.tar.gz
[root@hdss7-21 ~]# tar -xf jdk-8u231-linux-x64.tar.gz -C /data/nfs-volume/jenkins_home
[root@hdss7-21 ~]# cd /data/nfs-volume/jenkins_home
[root@hdss7-200 jenkins_home]# ll |grep jdk1.8.0_231
drwxr-xr-x.  7   10  143  245 Oct  5  2019 jdk1.8.0_231

[root@hdss7-200 jenkins_home]# cd maven-3.6.1-8u232/bin/

# mvn中指定使用JAVA_HOME,shell是一条一条执行的,一定要在使用$(JAVA_HOME)之前声明,所以选择在文件开头声明JAVA_HOME='/var/jenkins_home/jdk1.8.0_232' 
[root@hdss7-200 bin]# vi mvn  
JAVA_HOME='/var/jenkins_home/jdk1.8.0_231'

[root@hdss7-200 jenkins_home]# grep -v "^$\|^#" /data/nfs-volume/jenkins_home/maven-3.6.1-8u232/bin/mvn |head -n 5
JAVA_HOME='/var/jenkins_home/jdk1.8.0_231'
if [ -z "$MAVEN_SKIP_RC" ] ; then
  if [ -f /etc/mavenrc ] ; then
    . /etc/mavenrc
  fi
[root@hdss7-200 jenkins_home]# 

 删除jenkins容器,重启jenkins容器,然后重新使用参数化构建流水线

[root@hdss7-21 ~]# kubectl get pod -n infra
NAME                       READY   STATUS    RESTARTS   AGE
jenkins-56d9fd55f9-xkv5k   1/1     Running   2          115m

[root@hdss7-21 ~]# kubectl delete pod jenkins-56d9fd55f9-xkv5k -n infra
pod "jenkins-56d9fd55f9-xkv5k" deleted

五、制作JRE镜像底包

什么JRE底包,为什么要制作:

首先我们要知道,Dubbo微服务,主要是自动化构建java程序,其他程序也能构建。以构建java程序为例子,jenkins自动化构建java程序并封装成一个images镜像 ,jenkins首先需要拉起一个新的容器,然后给这个容器传递代码,然后在容器中使用meaven、jdk进行代码的编译,然后编译完成后,放入到tomcat的项目中,在编写这个镜像启动的时候,如何自启动tomcat,这一套流程,首先是不是需要一个基础的镜像,让jenkins拉起一个新的容器。这个基础的镜像,最好有jdk等组件。如果什么都没有,直接从官网下载一个centos镜像,在装jdk,那就太麻烦了。而这个基础的镜像就叫做底包。交付Dubbo微服务的提供者和消费者,都需要这个底包。

制作底包就是制作DockerFile,生产中直接在公网上下载java运行时环境(jre)的镜像,FROM这个镜像,然后安装一些我们需要的基础的架构,最后DockerFile成一个新的基础镜像(底包)。实际生产环境中,根据不同环境需要调整,或者根据当前的底包制作新的底包都可以。

java运行时环境(jre)的镜像是什么,跟jdk有什么区别。java程序通过jdk+meaven编译成字节码文件后,通过jre运行字节码文件,程序就可以正常工作。所以只要编译完代码后,只要有jre就行。而jdk是java发开工具包,里面包含java相关的所有工具,包括jre。所以我们只需要jre的image镜像作为最基础的镜像去做底包即可,jdk的镜像也可,但jdk的镜像没有jre的镜像小。所以第一步找到一个合适的运行时工作的底包。
docker pull docker.io/stanleyws/jre8:8u112    使用大于jdk1.7以上
docker pull docker.io/stanleyws/jre7:7u80      使用小于等于jdk1.7以下
正常的项目就40~50M,底包在300M,因为底包都一样,变化的就是jar包或者war包,随意调度速度快

1、制作DockerFile

[root@hdss7-200 ~]# docker pull docker.io/stanleyws/jre8:8u112
[root@hdss7-200 ~]# docker image ls -a |grep jre
stanleyws/jre8                       8u112            fa3a085d6ef1   4 years ago     363MB

[root@hdss7-200 ~]# docker image tag fa3a085d6ef1 harbor.od.com:180/public/jre8:8u112
[root@hdss7-200 ~]# docker login harbor.od.com:180
[root@hdss7-200~ ]# docker push harbor.od.com:180/public/jre8:8u112
[root@hdss7-200 ~]# mkdir /data/dockerfile/jre8;cd /data/dockerfile/jre8
[root@hdss7-200 dockerfile]# ll
drwxr-xr-x. 2 root root 78 12月 26 11:27 jenkins
drwxr-xr-x. 2 root root  6 12月 31 10:05 jre8

[root@hdss7-200 jre8]# vim Dockerfile

FROM harbor.od.com:180/public/jre8:8u112
ADD config.yml /opt/prom/config.yml
ADD jmx_javaagent-0.3.1.jar /opt/prom/
ADD entrypoint.sh /entrypoint.sh
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
WORKDIR /opt/project_dir
CMD ["/entrypoint.sh"]

解释:

FROM harbor.od.com/public/jre:8u112 底包

ADD config.yml /opt/prom/config.yml   普罗米修斯监控java程序用到的,config.yml文件记录匹配的规则比如rules:--- pattern: '.*'  (代表只要能给的,java毫无保留给普罗米修斯)

ADD jmx_javaagent-0.3.1.jar /opt/prom/   此.jar包是为了后期集群监控软件--普罗米修斯能够拿到监控数据。原理是:运行java的时候,运行命令的参数加上jmx_javaagent-0.3.1.jar后,jar包就能收集这个程序的jvm使用状况,就相当于一个客户端。普罗米修斯,通过这个.jar的接口获取jvm的信息。这个jmx_javaagent-0.3.1.jar只需要wget下载就行

ADD entrypoint.sh /entrypoint.sh    docker运行时默认的启动脚本

RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone   调整时区

WORKDIR /opt/project_dir   容器启动后默认进入此目录作为工作目录,所有的后续执行,如果没有切换目录都在此目录中

CMD ["/entrypoint.sh"]  启动容器后,先执行entrypoint.sh

[root@hdss7-200 jre8]# wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.3.1/jmx_prometheus_javaagent-0.3.1.jar -O jmx_javaagent-0.3.1.jar

[root@hdss7-200 jre8]# du -sh jmx_javaagent-0.3.1.jar  # 很小不影响业务运行
360K    jmx_javaagent-0.3.1.jar
[root@hdss7-200 docker_files]# vim entrypoint.sh  # 定义了三个变量,增加一条启动java的命令

#!/bin/sh
M_OPTS="-Duser.timezone=Asia/Shanghai -javaagent:/opt/prom/jmx_javaagent-0.3.1.jar=$(hostname -i):${M_PORT:-"12346"}:/opt/prom/config.yml"
C_OPTS=${C_OPTS}
JAR_BALL=${JAR_BALL}
exec java -jar ${M_OPTS} ${C_OPTS} ${JAR_BALL}

解释:

M_OPTS="-Duser.timezone=Asia/Shanghai -javaagent:/opt/prom/jmx_javaagent-
0.3.1.jar=$(hostname -i):${M_PORT:-"12346"}:/opt/prom/config.yml"     
java的启动参数,-Duser.timezone指定java的时区。/opt/prom/jmx_javaagent-0.3.1.jar使用刚才创
建的收集jVM的javaagent。=$(hostname -i) 等于docker IP也叫pod IP。 所以就是把pod 的IP传到
javaagent。${M_PORT:-"12346"} 使用的端口,M_PORT:-"12346" 为M_PORT默认数值12346,如果你没
有给环境变量传M_PORT等于多少,他就会使用默认数值M_PORT=12346。/opt/prom/config.yml 匹配的
规则。

C_OPTS= ${C_OPTS} 定义的是apollo的参数,也是一样dp.yaml传递环境变量参数,可以不写,因为不声明,${C_OPTS}也会默认从环境变量获取。

JAR_BALL=${JAR_BALL}  在这个脚本中定义一个变量JAR_BALL,${JAR_BALL}的意思是从我当前容器
运行的系统环境变量面取JAR_BALL的值,此处对应的是deployment.yaml中(name: JAR_BALL value: 
dubbo-server.jar)。所以整体意思是,jenkins把代码编译成了dubbo-server.jar,
然后放入到/opt/project_dir目录中(jenkins构建流水线脚本参数写到放入这里),entrypoint.sh也
是在/opt/project_dir目录中,容器启动后会立马执行/opt/project_dir/entrypoint.sh, 脚本执行到
JAR_BALL=${JAR_BALL},意思是JAR_BALL=dubbo-server.jar,然后后面的exec就会调用dubbo-
server.jar,把.jar项目运行起来、其实这个操作可以不写,因为不声明,${JAR_BALL}也会默认从环
境变量获取。

exec java -jar ${M_OPTS} ${C_OPTS} ${JAR_BALL}  执行java的命令
思考:java -jar ${M_OPTS} ${C_OPTS} ${JAR_BALL} 就是java启动的命令,exec又是干什么的?
回答:dockerfile做完的镜像,让镜像成为容器,容器启动的第一条命令是执行/entrypoint.sh,也就
是entrypoint.sh脚本的pid为1。而docker进程如果能一直RUNING状态吗,就是夯住,必须要保持pid=1
的进程一直在前台运行,只有前台运行,进程才会一直卡着,让docker一直在工作,不能宕掉,如果
pid=1的进程不能夯住,docker就会变成EXITED退出。而entrypoint.sh脚本中,三个都是变量,只有最
后一条,如果写成java -jar ${M_OPTS} ${C_OPTS} ${JAR_BALL},程序运行完成之后,不会夯住,直
接在后台运行。导致entrypoint.sh脚本也退出,docker直接EXITED退出,而加一个exec运行java -jar 
${M_OPTS} ${C_OPTS} ${JAR_BALL},这个java -jar ${M_OPTS} ${C_OPTS} ${JAR_BALL}语句就会代替
当前这个entrypoint.sh shell脚本的进程,变成pid等于1的进程,java -jar ${M_OPTS} ${C_OPTS} 
${JAR_BALL}就会变成pid等于1,并且在前台运行

[root@hdss7-200 docker_files]# chmod +x entrypoint.sh
[root@hdss7-200 jre8]# vim config.yml

rules:
  - pattern: '.*'

[root@hdss7-200 jre8]# ll

-rw-r--r--. 1 root root     25 Mar 29 09:07 config.yml
-rw-r--r--. 1 root root    297 Mar 29 08:21 Dockerfile
-rwxr-xr-x. 1 root root    234 Mar 29 08:39 entrypoint.sh
-rw-r--r--. 1 root root 367417 May 10  2018 jmx_javaagent-0.3.1.jar

2、build镜像到base仓库 

2.1、base:所有的底包

2.2、build镜像到base仓库

[root@hdss7-200 jre8]# docker image build -t harbor.od.com:180/base/jre8:8u112 ./

Sending build context to Docker daemon  372.2kB
Step 1/7 : FROM harbor.od.com:180/public/jre8:8u112
 ---> fa3a085d6ef1
Step 2/7 : ADD config.yml /opt/prom/config.yml
 ---> a0ee7f22e676
Step 3/7 : ADD jmx_javaagent-0.3.1.jar /opt/prom/
 ---> bd6f1bebfc18
Step 4/7 : ADD entrypoint.sh /entrypoint.sh
 ---> 06e90e726a97
Step 5/7 : RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
 ---> Running in d95f09966069
Removing intermediate container d95f09966069
 ---> 156268ed7f61
Step 6/7 : WORKDIR /opt/project_dir
 ---> Running in 9e6c0af8cd97
Removing intermediate container 9e6c0af8cd97
 ---> 3a8d1eebd488
Step 7/7 : CMD ["/entrypoint.sh"]
 ---> Running in c6a159441fce
Removing intermediate container c6a159441fce
 ---> 3a43af56c79b
Successfully built 3a43af56c79b
Successfully tagged harbor.od.com:180/base/jre8:8u112

[root@hdss7-200 jre8]# docker login harbor.od.com:180
[root@hdss7-200 jre8]# docker image push harbor.od.com:180/base/jre8:8u112

底包:比如项目中需要加特殊配置或者其他文件,只需简要做成底包,项目引用底包(鼠标点点),实现了新的项目

六、构建和交付dubbo

1、交付dubbo服务的提供者

优点:使用jenkins能进行持续构建dubbo服务的项目

1.1、配置Jenkins流水线

由于实验要求:确保Jenkins的admin账户的密码是admin123,如果不是修改密码

参数化构建流水线,这样流水线就能适配我们Dubbo微服务的提供者和消费者

配置我们保留3天,30份保留记录

 添加参数:String 字符串类型  choice 可选择的

1.2、Jenkins配置项目的10个参数

jenkins流水线配置的java项目的十个常用参数:

参数名(name)

类型(type)默认Trim the string描述(description)
app_namestring Parameeter项目名称,如 dubbo-demo-service
image_namestring Parameeterdocker镜像名称,如  harbor.od.com:180/app/dubbo-demo-service
git_repostring Parameeter项目在git版本仓库的地址,如 https://gitee.com/xxx/dubbo-demo-web
git_verstring Parameeter项目在git仓库中对应的分支或者版本号
add_tagstring Parameeter日期-时间,和git_ver拼在一起组成镜像的tag,如: 202002011001
mvn_dirstring Parameeter./在哪个目录执行编译,由开发同事提供
target_dirstring Parameeter./target编译的jar/war文件存放目录,由开发同事提供
mvn_cmdstring Parameetermvn clean package -Dmaven.test.skip=true执行编译所用的指令
base_imagechoice Parameeterbase/jre7:7u80
base/jre8:8u112
项目使用的jre底包
mavenchoice Parameeter3.6.1-8u232
3.2.5-7u045
2.2.1-6u025
编译时使用的maven目录中的版本号部分

解释:

app_name      是这个项目的名字
image_name  是调用哪个镜像
git_repo          项目从那个git仓库拉取,如 https://gitee.com/xxx/dubbo-demo-web

git_ver  分支或者版本号,里面可以填写分支号或者commit ID号

在https://gitee.com/jerry00713/dubbo-demo-web项目中有分支的,可能有master分支或者apollo分支,如果想编译master分支项目,必须指定拉取这个分支上的代码,jenkins使用 git clone git_repo -b git_ver (例如git clone https://gitee.com/xxx/dubbo-demo-web -b master

每提交一次代码,就会生成一个 commitid,这个commitid是独一无二的,只要提交一次就会生成一个。jenkins使用 git reset --hard [commit-number] 语法,也就是 git git_repo reset --hard  git_ver(git https://gitee.com/jerry00713/dubbo-demo-web reset --hard b6fae70)从而获取这次提交的代码

使用这种commitid最好的好处在于,如果一旦程序出问题,开发为了免责,把代码修改没问题后commit提交了,并且提交到master分支,这个时候由于你编译的时候,调用的是master分支代码,尽管是研发没修改之前的出问题代码,但是打成包镜像的时候,显示的还是harbor.od.com:180/app/dubbo-demo-service:master_210108_1435,因为jenkins默认把git_ver作为tag标签,导致责任就是你运维的锅。但是如果使用commitid作为git_ver ,打成的镜像就是harbor.od.com:180/app/dubbo-demo-service:b6fae70_210108_1435,commitid是独一无二的,问题一下就知道了谁的责任

add_tag   给docker镜像增加标签,add_tag是docker镜像标签的一部分,可以任意定义。生产:业务系统 (git_ver+add_tag任意定义标签。而自定义的标签一般为:日期_时间,和git_ver拼在一起组成镜像的tag,如: master_20200201_1001

mvn_dir    在哪个目录对这个项目的代码就行编译操作,jenkins从git上拉取下来的是如下的源代码,而编译这个代码的时候,是在那个目录下编译呢,是在根,根代表的是(./)当前这个目录,就是如下这个目录有(.gitee  dubbo-api dubbo-server REAMDE.md pox.xml 的目录),这个需要问开发,如果目录错误的话,假如在./dubbp-api下进行编译,编译过程中,代码写死需要调用./pom.xml,如果在./dubbp-api下编译,根本找不到./dubbp-api/pom.xml


target_dir   编译出来的项目,jar包或者wa包,编译后的放在哪里,由开发提供
mvn_cmd  执行编译所用的命令,这个命令就是meaven的命令(代码由meaven才能编译成.jar或.war),常用的是mvn clean package -e- q  -Dmaven.test.skip=true (Dmaven.test.skip跳出单元测试)​​​​​​​
base_image 用哪个底包,根据实际需要有多少列出多少
maven  执行编译使用的maven软件版本,根据实际需要有多少列出多少

注:Trim the string当你在填写参数的时候,帮你自动清楚前后空格

jenkins如何使用上述参数进行构建项目打包成image,由如下脚本使用这些参数构建,他的语法通过类似于shell的语句

pipeline {
  agent any 
    stages {
      stage('pull') { //get project code from repo 
        steps {
          sh "git clone ${params.git_repo} ${params.app_name}/${env.BUILD_NUMBER} && cd ${params.app_name}/${env.BUILD_NUMBER} && git checkout ${params.git_ver}"
        }
      }
      stage('build') { //exec mvn cmd
        steps {
          sh "cd ${params.app_name}/${env.BUILD_NUMBER}  && /var/jenkins_home/maven-${params.maven}/bin/${params.mvn_cmd}"
        }
      }
      stage('package') { //move jar file into project_dir
        steps {
          sh "cd ${params.app_name}/${env.BUILD_NUMBER} && cd ${params.target_dir} && mkdir project_dir && mv *.jar ./project_dir"
        }
      }
      stage('image') { //build image and push to registry
        steps {
          writeFile file: "${params.app_name}/${env.BUILD_NUMBER}/Dockerfile", text: """FROM harbor.od.com:180/${params.base_image}
ADD ${params.target_dir}/project_dir /opt/project_dir"""
          sh "cd  ${params.app_name}/${env.BUILD_NUMBER} && docker build -t harbor.od.com:180/${params.image_name}:${params.git_ver}_${params.add_tag} . && docker push harbor.od.com:180/${params.image_name}:${params.git_ver}_${params.add_tag}"
        }
      }
    }
}

 agent    # 步骤
   
stage('pull')          # pull 拉取git镜像
   stage('build')        # build 把代码构建成.jar项目
 
 stage('package')  # jar项目放入到指定目录
   stage('image')      # 打包成image包,提交镜像到harbor

1.3、构建Dubbo服务的提供者

1.3.1、如何进入参数填写

或者

1.3.2、参数填写,构建流水线参数一定不要写错了

注:若使用的是我上面提供的gitee Jerry00713/dubbo-demo-service代码,一定要按照图片内容填写
app_name   可以随意填写,但尽量跟实际的项目是一个名字,为了统一
image_name   格式为namespace/项目名,尽量不改,图中使用了app的名空间
git_repo 、git_ver   按照实际的情况,填写gitee
add_tag   可以随意填写,为了规范,标准写法为(年后2位+月+日_时间),这种格式为帮助你甩锅用,一旦出问题,可以按照时间来反编译看到底是谁的问题
mvn_dir   不要改,需要问研发应该在哪编译
mvn_cmd  不要改,需要问研发如何编译代码
target_dir  不要改,需要问研发编译出来的项目放在哪里,正常看pom.xml中的<module>dubbo-server</module>

1.3.3、 上述中,image_name打包的镜像要推送到app仓库,由于没有app仓库,需要创建

1.3.4  点击build就会编译

1.4、查看进度

1.4.1  查看进度日志

编译后产生序列号,点击#1

点击Console Output  查看安装过程

注释:

第一步克隆+ git clone Jerry00713/dubbo-demo-service dubbo-demo-service/1

提示成功,提示构建docker image

提示安装成功

1.4.2  编译失败重新编译

注意事项:如果在build后,查看Console Output 最后提示失败failure。首先查看Console Output提示的信息,是到哪步错误了。其中有可能是build配置页面填写信息的时候写错了,比如image_name写成了app/ dubbo-demo-service带空格了,或者target_dir写成了./dubbo-service/target。

还有可能是meaven跟jdk不匹配,或者meaven编译过程需要拉取基础组件,网络不通导致拉取不到等等。在排查并解决问题后,需要重新build构建。步骤是重新点击build with parameters→填写正确后信息,重新点击built,由于你没有删除之前失败的dubbo-demo-service的项目,所以他会保留之前已经构建的数据,从失败的地方重新继续built,并且会重新生成一个序列号。在失败点重新built,会节省时间,之前的操作直接跳过

1.5、查看image_name镜像

1.6、交付到k8s

回头看已经有了这个镜像,所以我们需要交付到k8s,所以我们需要资源配置清单

1.6.1、资源配置清单:

提供者只需要delpoyment资源的pod控制器,因为不需要ingress让外部访问,也不需要其他资源通过service资源跟我通信,我只需要把我的信息传递给注册中心,然后注册中心的消费者通过注册中心记录,如何调用我的接口。

[root@hdss7-200 k8s-yaml]# mkdir /data/k8s-yaml/dubbo-demo-service;cd /data/k8s-yaml/dubbo-demo-service
[root@hdss7-200 dubbo-demo-service]# vi dp.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: dubbo-demo-service
  namespace: app
  labels:
    name: dubbo-demo-service
spec:
  replicas: 1
  selector:
    matchLabels:
      name: dubbo-demo-service
  template:
    metadata:
      labels:
        app: dubbo-demo-service
        name: dubbo-demo-service
    spec:
      containers:
      - name: dubbo-demo-service
        image: harbor.od.com:180/app/dubbo-demo-service:master_210108_1435
        ports:
        - containerPort: 20880
          protocol: TCP
        env:
        - name: JAR_BALL
          value: dubbo-server.jar
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: harbor
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      securityContext:
        runAsUser: 0
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600

解释:

metadata:
  name: dubbo-demo-service
  namespace: app       运行在app的名称空间下

  metadata:
      labels:     标签可以随便定义
        app: dubbo-demo-service
        name: dubbo-demo-service
  
        image: harbor.od.com:180/app/dubbo-demo-service:master_210108_1435        修改成刚才编译的镜像
        ports:   暴露rpc端口 ,写不写无所谓
        - containerPort: 20880  把容器内的20880端口,暴露到容器外,docker -P  20880:20880
          protocol: TCP
        env: 
        - name: JAR_BALL  制作JRE镜像底包的时候,构建DockerFile,使用了entrypoint.sh,在entrypoint.sh中定义一个变量JAR_BALL,怎么接收jar包的环境变量
          value: dubbo-server.jar   启动dubbo服务时候,传给容器的jar包
        imagePullPolicy: IfNotPresent    如果本地没有此镜像,在从harbor拉取镜像
      imagePullSecrets:    必须有,对应app名称空间相爱的secret,如果没有拉取不到app私有仓库镜像
      - name: harbor

创建app空间
[root@hdss7-21 ~]# kubectl create ns app
namespace/app created

创建app空间secret(因为app空间,要去harbor的私有仓库app拉取镜像,所以需要创建 secret,让app空间去请求私有仓库的时候,带着secret,secret记录的hartbor的账户密码,才能请求到镜像)
[root@hdss7-21 ~]# kubectl create secret docker-registry harbor --docker-server=harbor.od.com:180 --docker-username=admin --docker-password=Harbor12345 -n app
secret/harbor created

1.6.2、在交付到k8s之前查看zookeeper,对比交付后,在查看zookeeper

[root@hdss7-11 ~]# /opt/zookeeper/bin/zkServer.sh status   查看zookeeper启动状态
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: follower

[root@hdss7-11 ~]# /opt/zookeeper/bin/zkCli.sh -server localhost:2181   登录zookeeper
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] ls /        查看zookeeper目前节点,只有自己
[zookeeper]

1.6.3、资源配置清单交付到k8s

hdss7-21 或者hdss7-22
[root@hdss7-21 /]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-service/dp.yaml
deployment.extensions/dubbo-demo-service created

1.6.4、验证交付到k8s

查看zookeeper
[zk: localhost:2181(CONNECTED) 0] ls /        查看zookeeper目前节点
[dubbo,zookeeper]

[zk: localhost:2181(CONNECTED) 1] ls /dubbo   已经注册到了zk的注册中心
[com.od.dubbotest.api.HelloService]

查看容器是否启动

查看容器日志,提示Dubbo server 是启动

2、借助Blue Ocean 插件回顾Jenkins流水线配置

由于第5次配置成功了,打开Blue Ocean

点击状态5

讲解:

1、pull --拉取代码

jenkins默认的工作路径是/var/jenkins_home。jenkins在做参数化构建前的时候,首先我们会创建一个项目比如叫(Dubbo-demo),在jenkins中的workspace(工作环境)目录,对应的生成一个Dubbo-demo目录。然后再做参数化构建的时候,就在这个/var/jenkins_home/workspace/Dubbo-demo目录下进行。部署第一行说把代码克隆到dubbo-demo-service/5,其中5是序列号,每做一次参数化构建,必须生成一个新的序列号,否则都打在一个目录乱套了。dubbo-demo-service/5 在shell中省略了./ (就是./dubbo-demo-service/5),而所有的操作都在/var/jenkins_home/workspace/Dubbo-demo中,所以整体的意思为(git clone https://gitee.com/jerry00713/dubbo-demo-service.git  /var/jenkins_home/workspace/Dubbo-demo/dubbo-demno-service/5)  而/var/jenkins_home挂载在 /data/nfs-volume/jenkins_home/下

[root@hdss7-200 src]# cd /data/nfs-volume/jenkins_home/workspace/
[root@hdss7-200 workspace]# ll
drwxr-xr-x. 4 root root  59 1月   8 12:13 Dubbo-demo
drwxr-xr-x. 2 root root  6   1月   8 14:45 Dubbo-demo@tmp

[root@hdss7-200 workspace]# cd Dubbo-demo
[root@hdss7-200 Dubbo-demo]# ll
drwxr-xr-x. 5 root root 33 1月   8 14:37 dubbo-demo-service

[root@hdss7-200 Dubbo-demo]# cd dubbo-demo-service
[root@hdss7-200 dubbo-demo-service]# ll
drwxr-xr-x. 6 root root 101 1月   5 11:51 1
drwxr-xr-x. 6 root root 101 1月   8 12:07 2
drwxr-xr-x. 6 root root 119 1月   8 14:38 5

[root@hdss7-200 dubbo-demo-service]# cd 5
[root@hdss7-200 5]# ll

-rw-r--r--. 1 root root  93 1月   8 14:38 Dockerfile
drwxr-xr-x. 4 root root  46 1月   8 14:37 dubbo-api
drwxr-xr-x. 4 root root  46 1月   8 14:38 dubbo-server
-rw-r--r--. 1 root root 729 1月   8 14:37 pom.xml
-rw-r--r--. 1 root root 945 1月   8 14:37 README.md

git checkout master 意思为,切换到master分支
[root@hdss7-200 5]# git branch
* master

2、build --编译代码

+ /var/jenkins_home/maven-3.6.1-8u232/bin/mvn clean package -Dmaven.test.skip=true   mvn 进行编译代码

3、package --打包

cd 到参数化构建target,这里面创建podject_dir目录,然后把jar包放入

4、编写Dockerfile,做成docker镜像

 1、Write file to workspace 为生编写dockerfile:
[root@hdss7-200 ]# cd /data/nfs-volume/jenkins_home/workspace/Dubbo-demo/dubbo-demo-service/5
[root@hdss7-200 5]# ll

-rw-r--r--. 1 root root  93 1月   8 14:38 Dockerfile
drwxr-xr-x. 4 root root  46 1月   8 14:37 dubbo-api
drwxr-xr-x. 4 root root  46 1月   8 14:38 dubbo-server
-rw-r--r--. 1 root root 729 1月   8 14:37 pom.xml
-rw-r--r--. 1 root root 945 1月   8 14:37 README.md


[root@hdss7-200 5]# cat Dockerfile 
FROM harbor.od.com:180/base/jre8:8u112
ADD ./dubbo-server/target/project_dir /opt/project_dir[root@hdss7-200 5]# 

2、docker build 创建docker 的镜像,并提交到harbor

总结如下:

3交付Monitor到K8S

思考:在交付Dubbo生产者后,通过进入zk注册中心后,才能查看Dubbo生产者已经进入注册中心。这才是一个Dubbo生产者,也就是项目中的一个模块,再加上Dubbo消费者,一个项目会有若干个模块,也就是若干生产者、消费者,难道进入zk的命令行一个一个看。

我们需要一个zk图形界面判断有多少个提供者交付到了zk中,不能每次都敲命令看,这个界面叫做Monitor,他就是一个取注册中心的数据,并展现
目前比较流行的zk监控者:dubbo-admin  dubbo-Monitor
托管在:
GitHub - Jeromefromcn/dubbo-monitor

3.1、下载源代码,解压

[root@hdss7-200 dubbo-server]# cd /opt/src/
[root@hdss7-200 src]# rz dubbo-monitor-master
[root@hdss7-200 src]# unzip dubbo-monitor-master
[root@hdss7-200 src]# mv dubbo-monitor-master dubbo-monitor
[root@hdss7-200 src]# cp -a dubbo-monitor /data/dockerfile/
[root@hdss7-200 src]# cd /data/dockerfile/
[root@hdss7-200 dockerfile]# ll
drwxr-xr-x. 3 root root 69 7月  27 2016 dubbo-monitor
drwxr-xr-x. 2 root root 78 12月 26 11:27 jenkins
drwxr-xr-x. 2 root root 94 12月 31 13:59 jre8

3.2、修改dubbo-monitor配置

3.2.1、修改dubbo_origin.properties

[root@hdss7-200 src]# cd /data/dockerfile/dubbo-monitor
[root@hdss7-200 dubbo-monitor]# ll
-rw-r--r--.   1   root root 155 7月  27 2016 Dockerfile
drwxr-xr-x. 5  root root  40  7月  27 2016 dubbo-monitor-simple
-rw-r--r--.   1   root root  16  7月  27 2016 README.md

[root@hdss7-200 dubbo-monitor]# cd dubbo-monitor-simple/conf/

#  修改monitor​​​​​​​启动参数,比如启动占用什么端口,monitor的目录在哪,修改成下面的配置
[root@hdss7-200 conf]# vi dubbo_origin.properties 

dubbo.container=log4j,spring,registry,jetty
dubbo.application.name=dubbo-monitor
dubbo.application.owner=Jerry
dubbo.registry.address=zookeeper://zk1.od.com:2181?backup=zk2.od.com:2181,zk3.od.com:2181
dubbo.protocol.port=20880
dubbo.jetty.port=8080
dubbo.jetty.directory=/dubbo-monitor-simple/monitor
dubbo.charts.directory=/dubbo-monitor-simple/charts
dubbo.statistics.directory=/dubbo-monitor-simple/statistics
dubbo.log4j.file=logs/dubbo-monitor-simple.log
dubbo.log4j.level=WARN

解释:

dubbo.application.name=dubbo-monitor   monitor的名字随便起
dubbo.application.owner=Jerry   所属者名字随便起
dubbo.registry.address=zookeeper......  写我们自己的zookeeper地址
dubbo.protocol.port=20880     自定义monitor提供的 rpc接口,习惯统一用20880
dubbo.jetty.port=8080   monitor对外提供网站http接口
dubbo.jetty.directory=/dubbo-monitor-simple/monitor  monitor的工作目录,给了一个固定位置
dubbo.charts.directory=/dubbo-monitor-simple/charts  monitor的charts文件
dubbo.statistics.directory=/dubbo-monitor-simple/statistics  monitor的静态文件

3.2.2、修改start.sh

[root@hdss7-200 dubbo-monitor]# cd /data/dockerfile/dubbo-monitor
[root@hdss7-200 dubbo-monitor]# ll    # dubbo-monitor的开发者已经写好Dockerfile,帮你构建docker 镜像
-rw-r--r--.    1 root root 155 7月  27 2016 Dockerfile
drwxr-xr-x. 5 root root  40  7月  27 2016 dubbo-monitor-simple
-rw-r--r--.    1 root root  16  7月  27 2016 README.md

[root@hdss7-200 dubbo-monitor]# cat Dockerfile   # 查看Dockerfile

FROM jeromefromcn/docker-alpine-java-bash
MAINTAINER Jerome Jiang      # 谁做的
COPY dubbo-monitor-simple/ /dubbo-monitor-simple/  
CMD /dubbo-monitor-simple/bin/start.sh

# 查看Dockerfile其实很简单,除了start.sh启动脚本需要修改,按照实际项目修改,比如jvm、容器启动第一进程能否夯住

[root@hdss7-200 dubbo-monitor]# vim /data/dockerfile/dubbo-monitor/dubbo-monitor-simple/bin/start.sh

修改一:JVM调优,源代码给2g太大了,按照比例缩小改成128m,小m(兆)

if [ -n "$BITS" ]; then
    JAVA_MEM_OPTS=" -server -Xmx128m -Xms128m -Xmn32m -XX:PermSize=16m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
else
    JAVA_MEM_OPTS=" -server -Xms128m -Xmx128m -XX:PermSize=16m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
fi

修改二:由于nohup java不能保证docker一直保持RUNING的生命周期,所以默认提供的Dockerfile制作的镜像无法一直RUNING启动,需要修改启动参数,让 java 进程在前台运行,删除nohup java这行,及nohup java以下的行,因为下面的语句不是调配系统层等参数,而是为 nohup java语句做判断等,所以没用。删除后,增加自己的代码

方式一:vi 手动修改,删除不需要的内容,增加需要内容

删除不需要的内容:

 增加需要内容:就是上述的替换

echo -e "Starting the $SERVER_NAME ...\c"
exec java $JAVA_OPTS $JAVA_MEM_OPTS $JAVA_DEBUG_OPTS $JAVA_JMX_OPTS -classpath $CONF_DIR:$LIB_JARS com.alibaba.dubbo.container.Main > $STDOUT_FILE 2>&1

方式二:执行脚本,可以一句话搞定

sed -r -i -e '/^nohup/{p;:a;N;$!ba;d}' /data/dockerfile/dubbo-monitor/dubbo-monitor-simple/bin/start.sh && sed -r -i -e "s%^nohup(.*) &%exec\1%" /data/dockerfile/dubbo-monitor/dubbo-monitor-simple/bin/start.sh
sed -r -i -e '/^nohup/{p;:a;N;$!ba;d}'  sed 模式空间语法

解释:根据我们做dobbo微服务的底包的时候,使用exec让java命令占用脚本的pid,也就是等于1的pid,让java程序一直在前台跑。这里也是,让java命令取代pid为1的start.sh脚本,使其java命令是第一进程,pid=1,然后一直以第一进程夯在前台。

最后的修改结果:

3.3、build docker镜像

[root@hdss7-200 dubbo-monitor]# cd /data/dockerfile/dubbo-monitor
[root@hdss7-200 dubbo-monitor]# docker build . -t harbor.od.com:180/infra/dubbo-monitor:latest
[root@hdss7-200 dubbo-monitor]# docker login harbor.od.com:180
[root@hdss7-200 dubbo-monitor]# docker push harbor.od.com:180/infra/dubbo-monitor:latest

3.4、配置资源配置清单

发布docker镜像需要配置资源配置清单

[root@hdss7-200 ~]# mkdir -p /data/k8s-yaml/dubbo-monitor/
[root@hdss7-200 ~]# vim /data/k8s-yaml/dubbo-monitor/deployment.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: dubbo-monitor
  namespace: infra
  labels: 
    name: dubbo-monitor
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: dubbo-monitor
  template:
    metadata:
      labels: 
        app: dubbo-monitor
        name: dubbo-monitor
    spec:
      containers:
      - name: dubbo-monitor
        image: harbor.od.com:180/infra/dubbo-monitor:latest
        ports:
        - containerPort: 8080
          protocol: TCP
        - containerPort: 20880
          protocol: TCP
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: harbor
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      securityContext: 
        runAsUser: 0
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600

解释:
        image: harbor.od.com:180/infra/dubbo-monitor:latest
        ports:   暴露两个rpc端口
        - containerPort: 8080
          protocol: TCP
        - containerPort: 20880   
          protocol: TCP

[root@hdss7-200 ~]# vim /data/k8s-yaml/dubbo-monitor/service.yaml

kind: Service
apiVersion: v1
metadata: 
  name: dubbo-monitor
  namespace: infra
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector: 
    app: dubbo-monitor

解释:    
port: 8080   cluster IP暴露的端口,访问此service资源的集群IP:8080,通过kube-proxy反代到某一个节点的dubbo-monitor的pod的8080端口。cluster IP理论上写什么端口都行,因为在集群中,每个service资源从(192.168.0.0/16)中都会分配一个不同的IP地址,但注意,这里定义是8080端口,ingress资源中servicePort的端口必须也是8080,ingress资源需要通过此端口连接service资源
targetPort: 8080    docker里面的端口,需要跟cluster IP的端口做映射

[root@hdss7-200 ~]# vim /data/k8s-yaml/dubbo-monitor/ingress.yaml

kind: Ingress
apiVersion: extensions/v1beta1
metadata: 
  name: dubbo-monitor
  namespace: infra
spec:
  rules:
  - host: dubbo-monitor.od.com
    http:
      paths:
      - path: /
        backend: 
          serviceName: dubbo-monitor
          servicePort: 8080

3.5、应用资源配置清单

[root@hdss7-21 /]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/deployment.yaml
deployment.extensions/dubbo-monitor created
[root@hdss7-21 /]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/service.yaml
service/dubbo-monitor created
[root@hdss7-21 /]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/ingress.yaml
ingress.extensions/dubbo-monitor created

3.5.1、如果容器报错CrashLoopBackOff 

[root@hdss7-21 /]# kubectl get pods -o wide -n infra

NAME                             READY   STATUS             RESTARTS   AGE    IP            NODE                NOMINATED NODE   READINESS GATES
dubbo-monitor-76f9845456-fdqbp   0/1     CrashLoopBackOff   5          4m8s   172.7.22.5    hdss7-22.host.com   <none>           <none>
jenkins-64ff665996-q642m         1/1     Running            0          2d     172.7.21.10   hdss7-21.host.com   <none>           <none>

查看容器日志:

[root@hdss7-21 /]# kubectl logs dubbo-monitor-76f9845456-nd4lh -n infra
starting the dubbo-monitor.............[root@hdss7-21 /]#   说明一直在启动

[root@hdss7-21 /]# kube ctl descirbe pod  dubbo-monitor-76f9845456-nd4lh -n infra    总结:就是Back-off restarting failed container
  Normal   Scheduled  5m46s                    default-scheduler           Successfully assigned infra/dubbo-monitor-5cf4bb98d5-vkxc8 to hdss7-22.host.com
  Normal   Pulled     4m10s (x5 over 5m41s)  kubelet, hdss7-22.host.com  Container image "harbor.od.com:180/infra/dubbo-monitor:latest" already present on machine
  Normal   Created    4m10s (x5 over 5m41s)  kubelet, hdss7-22.host.com  Created container dubbo-monitor
  Normal   Started    4m10s (x5 over 5m40s)   kubelet, hdss7-22.host.com  Started container dubbo-monitor
  Warning  BackOff    40s (x23 over 5m35s)    kubelet, hdss7-22.host.com   Back-off restarting failed container
[root@hdss7-21 /]# 

解决方案:
1、一直启动,说明启动镜像的时候那个地方卡住了,在build如果无问题,就需要查看制作镜像Dockerfile有无问题,但Dockerfile是官方的,而且里面除了刚刚修改的start.sh,无其他大的变动。查看start.sh后是可能是修改JVM的时候128m,写成128g,导致资源耗尽
2、还有种可能是在deployment.yaml 中 progressDeadlineSeconds: 600   多长时间运行容器不正常,判断为失败,所以是不是没写这句导致容器提前死亡
操作过程:
如上问题修改128m,修改progressDeadlineSeconds: 600 ,然后删除harbor中的dubbo-monitor镜像,删除hdss7-200本地的dubbo-monitor镜像,重新build 。由于修改deployment.yaml,重新kubectl apply -f deployment.yaml,由于生成的dubbo-monitor-76f9845456-nd4lh的时候,会拉取barbor镜像下载本地,而且在deployment.yaml中 IfNotPresent (如果本地没有在拉取远程镜像),由于本地已经有,所以在启动不会拉取harbor镜像。所以需要删除已经下载的本地dubbo-monitor镜像。

3.5.2、查看状态:

没有日志,没有重定向标准输出

3.6、访问Monitor

解析原理:访问dubbo-monitor.od.com,通过named解析到10.4.7.10(vip),通过7层代理,指给了某一个ingress控制器,ingress根据访问的路径解析,需要抛给那个service资源,service资源通过kube-proxy把流量抛给某一个monitor的pod

3.6.1、 配置DNS解析
[root@hdss7-11 ~]# vi /var/named/od.com.zone

$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2020010507 ; serial                  前滚+1
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
$TTL 60 ; 1 minute
dns                A    10.4.7.11
harbor             A    10.4.7.200
k8s-yaml           A    10.4.7.200
traefik            A    10.4.7.10
dashboard          A    10.4.7.10
zk1                A    10.4.7.11
zk2                A    10.4.7.12
zk3                A    10.4.7.21
jenkins            A    10.4.7.10
dubbo-monitor      A    10.4.7.10

注:dubbo-monitor是通过ingress.yaml的- host: dubbo-monitor.od.com  得来的                      

[root@hdss7-11 ~]# systemctl restart named
[root@hdss7-11 ~]# dig -t A dubbo-monitor.od.com @10.4.7.11 +short
10.4.7.10

3.6.2、 访问页面

访问​​​​​​​http://dubbo-monitor.od.com/

点击status查看目前注册中心的状态:

registry OK  zk1.od.com:2181(connected)   monitor连接的哪个zk
server   OK  /172.7.22.6:20880(clients:0)     monitor对外的地址(monitord的podIP:端口)

点击Applications查看已经注册到注册中心的项目:

dubbo-monitor  自己建立的monitor,名字也是dubbo_origin.properties修改的Jerry
dubbo-demo-service   从zk中读取出来的提供者

点击Applications →​​​​​​​ dubbo-demo-service,查看此项目的情况:

提供两个rpc的api接口

3.6、将dubbo_origin.properties 配置成configmap

将dubbo_origin.properties 配置成configmap,实现动态修改连接那个zk

3.6.1、配置configmap清单

[root@hdss7-200 ~]# cd /data/k8s-yaml/dubbo-monitor
[root@hdss7-200 dubbo-monitor]# vi cm.yaml 

apiVersion: v1
kind: ConfigMap
metadata:
  name: dubbo-monitor-cm 
  namespace: infra
data:
  dubbo.properties: |
    dubbo.container=log4j,spring,registry,jetty
    dubbo.application.name=dubbo-monitor
    dubbo.application.owner=Jerry
    dubbo.registry.address=zookeeper://zk1.od.com:2181?backup=zk2.od.com:2181,zk3.od.com:2181
    dubbo.protocol.port=20880
    dubbo.jetty.port=8080
    dubbo.jetty.directory=/dubbo-monitor-simple/monitor
    dubbo.charts.directory=/dubbo-monitor-simple/charts
    dubbo.statistics.directory=/dubbo-monitor-simple/statistics
    dubbo.log4j.file=logs/dubbo-monitor-simple.log
    dubbo.log4j.level=WARN

3.6.2、修改deployment,使其调用configmap中的dubbo.properties

[root@hdss7-200 dubbo-monitor]# vi deployment.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: dubbo-monitor
  namespace: infra
  labels: 
    name: dubbo-monitor
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: dubbo-monitor
  template:
    metadata:
      labels: 
        app: dubbo-monitor
        name: dubbo-monitor
    spec:
      volumes:
       - name: configmap-volume
         configMap:
           name: dubbo-monitor-cm
      containers:
      - name: dubbo-monitor
        image: harbor.od.com:180/infra/dubbo-monitor:latest
        ports:
        - containerPort: 8080
          protocol: TCP
        - containerPort: 20880
          protocol: TCP
        volumeMounts:
        - name: configmap-volume
          mountPath: /dubbo-monitor-simple/conf
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: harbor
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      securityContext: 
        runAsUser: 0
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600
[root@hdss7-200 dubbo-monitor]# 

3.6.3、应用deployment、configmap

[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/cm.yaml
configmap/dubbo-monitor-cm created
[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/deployment.yaml
deployment.extensions/dubbo-monitor configured
[root@hdss7-21 ~]# 

3.6.4、等容器启动后查看http://dubbo-monitor.od.com/,能访问代表无问题

3.6.5、configmap声明dubbo.properties文件

不知道有没有注意,在声明configmap的时候,配置的是dubbo.properties文件,也就是给容器创建一个/dubbo-monitor-simple/conf/dubbo.properties,而我们在没用configmap部署的时候,明明是修改的是conf/dubbo.properties,按道理应该是声明的/dubbo-monitor-simple/conf/dubbo_origin.properties

 做实验看看就知道了,修改configmap为dubbo_origin.properties

 应用cm,并重启dubbo-monitor的pod

[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/dubbo-monitor/cm.yaml
configmap/dubbo-monitor-cm configured

 会发现容器报错了

查看日志,意思是没有conf/dubbo.properties 这个文件,这个文件又是什么? 

 修改deployment资源,使其不调度configmap,进去容器看到底是啥

启动容器后,进入容器,查看dubbo-monitor-simple/conf/目录下竟然有dubbo.properties,dubbo.properties到底是啥?

[root@hdss7-21 ~]# kubectl get pod -n infra
NAME                             READY   STATUS    RESTARTS   AGE
apollo-portal-66795c5b59-j5kd6   1/1     Running   5          5d9h
dubbo-monitor-76f9845456-x2g97   1/1     Running   0          47s
jenkins-56d9fd55f9-p4ldd         1/1     Running   13         11d

[root@hdss7-21 ~]# kubectl exec -it dubbo-monitor-76f9845456-x2g97 -n infra /bin/bash
bash-4.3# ls
bin                   home                  mnt                   sbin                  var
dev                   lib                   proc                  sys
dubbo-monitor-simple  linuxrc               root                  tmp
etc                   media                 run                   usr
bash-4.3# cd dubbo-monitor-simple/conf/
bash-4.3# ls
dubbo.properties         dubbo_origin.properties

 查看dubbo.properties,就是dubbo_origin.properties内容

bash-4.3# cat dubbo.properties 
##
# Copyright 1999-2011 Alibaba Group.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
dubbo.container=log4j,spring,registry,jetty
dubbo.application.name=dubbo-monitor
dubbo.application.owner=Jerry
dubbo.registry.address=zookeeper://zk1.od.com:2181?backup=zk2.od.com:2181,zk3.od.com:2181
#dubbo.registry.address=zookeeper://127.0.0.1:2181
#dubbo.registry.address=redis://127.0.0.1:6379
#dubbo.registry.address=dubbo://127.0.0.1:9090
dubbo.protocol.port=20880
dubbo.jetty.port=8080
dubbo.jetty.directory=/dubbo-monitor-simple/monitor
dubbo.charts.directory=/dubbo-monitor-simple/charts
dubbo.statistics.directory=/dubbo-monitor-simple/statistics
dubbo.log4j.file=logs/dubbo-monitor-simple.log
dubbo.log4j.level=WARN

bash-4.3# cat dubbo_origin.properties 
##
# Copyright 1999-2011 Alibaba Group.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
dubbo.container=log4j,spring,registry,jetty
dubbo.application.name=dubbo-monitor
dubbo.application.owner=Jerry
dubbo.registry.address=zookeeper://zk1.od.com:2181?backup=zk2.od.com:2181,zk3.od.com:2181
#dubbo.registry.address=zookeeper://127.0.0.1:2181
#dubbo.registry.address=redis://127.0.0.1:6379
#dubbo.registry.address=dubbo://127.0.0.1:9090
dubbo.protocol.port=20880
dubbo.jetty.port=8080
dubbo.jetty.directory=/dubbo-monitor-simple/monitor
dubbo.charts.directory=/dubbo-monitor-simple/charts
dubbo.statistics.directory=/dubbo-monitor-simple/statistics
dubbo.log4j.file=logs/dubbo-monitor-simple.log
dubbo.log4j.level=WARN

bash-4.3# 

所以猜测应该程序把dubbo_origin.properties复制一份并改了个名字dubbo.properties,至于为什么也不清楚,所以其实程序真正调用dubbo.properties

4、交付dubbo服务的消费者

需要通过 jenkins 进行持续继承。构建提供者时候,做过流水线,消费者也可以。两个服务可以通过一个流水线完成

4.1、构建流水线

4.1.1、点击构建

4.1.2、构建填写

注:

app-name:dubbo-demo-consumer    名字随便起,建议使用项目名称
image-name:app/dubbo-demo-consumer   app不能省,到时候要推送到app私有的仓库
git_repo:git@gitee.com:jerry00713/dubbo-demo-web.git   这里注意,由于代码放到了git私有仓库(dubbo-demo-web),无法使用http形式拉取私有仓库代码。之前做过把ssh的私钥拷贝到了jenkins容器,在把ssh公钥传到了私有仓库(dubbo-demo-web),就可以使用ssh形式clone代码
git_ver:master  使用master代码分支
mvn_dir:./   不能改,代码规定要在根目录下编译
target_dir:./dubbo-client/target     不能改,代码规定编译后的.jar包放在此目录,才能运行
mvn clean package -Dmaven.test.skip=true  生产上可以写添加 -e -q 参数(mvn clean package -e -q -Dmaven.test.skip=true ) 。 -q 静默输出  -e 只有错误输出没有错误不输出。在Console Output中不会显示从公网上下载的那些jar包。

4.1.3、Bulid后查看Console Output

+ git clone git@gitee.com:jerry00713/dubbo-demo-web.git dubbo-demo-consumer/12

[INFO] dubbotest-api ...................................... SUCCESS [ 11.912 s]
[INFO] dubbotest-client ................................... SUCCESS [ 12.968 s]
[INFO] demo ............................................... SUCCESS [  0.021 s]

+ docker build -t harbor.od.com:180/app/dubbo-demo-consumer:master_210110_1420 .

Finished: SUCCESS

扩展:第一次使用Blue Ocean参数化构建的时候(部署生产者的时候),构建很慢,而且有大量的从公网上下载的一些jar包,这次构建消费者很快,为什么?是由于构建一次后,jenkins会把java依赖的一些jar包,下载后落在本地缓存中,如果再次构建的时候,就会重新拿来使用。具体目录如下(/root/.m2/repository)。在生产上,可以把.m2目录也挂在出来,这样重启jenkins就不会丢

[root@hdss7-21 ~]# kubectl get pod -n infra
NAME                             READY   STATUS    RESTARTS   AGE
dubbo-monitor-76f9845456-424bh   1/1     Running   0          139m
jenkins-56d9fd55f9-p4ldd         1/1     Running   3          41h

[root@hdss7-21 ~]# kubectl exec -it jenkins-56d9fd55f9-p4ldd -n infra /bin/bash
root@jenkins-56d9fd55f9-p4ldd:/# cd /root/.m2/;ls -l
total 0
drwxr-xr-x. 18 root root 261 Mar 31 13:30 repository

root@jenkins-56d9fd55f9-p4ldd:~/.m2# cd repository/
root@jenkins-56d9fd55f9-p4ldd:~/.m2/repository# ls -l
total 0
drwxr-xr-x.  3 root root  25 Mar 31 13:28 aopalliance
drwxr-xr-x.  8 root root 106 Mar 31 13:30 asm
drwxr-xr-x.  3 root root  38 Mar 31 13:27 backport-util-concurrent
drwxr-xr-x.  3 root root  17 Mar 31 13:28 ch
drwxr-xr-x.  3 root root  25 Mar 31 13:26 classworlds
drwxr-xr-x.  6 root root  66 Mar 31 13:29 com
drwxr-xr-x.  3 root root  25 Mar 31 13:27 commons-cli
drwxr-xr-x.  3 root root  24 Mar 31 13:30 commons-io
drwxr-xr-x.  3 root root  26 Mar 31 13:28 commons-lang
drwxr-xr-x.  4 root root  56 Mar 31 13:29 commons-logging
drwxr-xr-x.  3 root root  19 Mar 31 13:29 io
drwxr-xr-x.  6 root root  74 Mar 31 13:29 javax
drwxr-xr-x.  3 root root  19 Mar 31 13:29 jline
drwxr-xr-x.  3 root root  19 Mar 31 13:26 junit
drwxr-xr-x.  3 root root  19 Mar 31 13:27 log4j
drwxr-xr-x. 19 root root 265 Mar 31 13:30 org
root@jenkins-56d9fd55f9-p4ldd:~/.m2/repository# 

4.1.4、查看是否成功

1、Console Output提示成功后,检查harbor是否有对应的镜像
2、如果有问题,查看 Blue Ocean

4.2、配置资源配置清单

[root@hdss7-200 ~]# cd /data/k8s-yaml/
[root@hdss7-200 k8s-yaml]# mkdir dubbo-demo-consumer
[root@hdss7-200 k8s-yaml]# cd dubbo-demo-consumer/

[root@hdss7-200 dubbo-demo-consumer]# vi deployment.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: dubbo-demo-consumer
  namespace: app
  labels: 
    name: dubbo-demo-consumer
spec:
  replicas: 1
  selector:
    matchLabels: 
      name: dubbo-demo-consumer
  template:
    metadata:
      labels: 
        app: dubbo-demo-consumer
        name: dubbo-demo-consumer
    spec:
      containers:
      - name: dubbo-demo-consumer
        image: harbor.od.com:180/app/dubbo-demo-consumer:master_210110_1420
        ports:
        - containerPort: 8080
          protocol: TCP
        - containerPort: 20880
          protocol: TCP
        env:
        - name: JAR_BALL
          value: dubbo-client.jar
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: harbor
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      securityContext: 
        runAsUser: 0
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 1
      maxSurge: 1
  revisionHistoryLimit: 7
  progressDeadlineSeconds: 600

注:JAR_BALL中的数值,是mvn编译后项目的jar包,根据代码不同,产生的jar包也不同,由消费者代码编译后的项目名称叫dubbo-client.jar。提供者代码编译后的项目名称叫dubbo-server.jar。所以消费者dp.yaml的env (JAR_BALL=dubbo-client.jar),提供者是(JAR_BALL=dubbo-server.jar)。

[root@hdss7-200 dubbo-demo-consumer]# vi service.yaml

kind: Service
apiVersion: v1
metadata: 
  name: dubbo-demo-consumer
  namespace: app
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector: 
    app: dubbo-demo-consumer

[root@hdss7-21 ~]# vi ingress.yaml  # 因为消费者是提供给人操作的web页面项目

kind: Ingress
apiVersion: extensions/v1beta1
metadata: 
  name: dubbo-demo-consumer
  namespace: app
spec:
  rules:
  - host: demo.od.com
    http:
      paths:
      - path: /
        backend: 
          serviceName: dubbo-demo-consumer
          servicePort: 8080

4.3、 配置DNS解析

[root@hdss7-11 ~]# vi /var/named/od.com.zone

$ORIGIN od.com.
$TTL 600        ; 10 minutes
@               IN SOA  dns.od.com. dnsadmin.od.com. (
                                2020010508 ; serial          前滚+1
                                10800      ; refresh (3 hours)
                                900        ; retry (15 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
                                NS   dns.od.com.
$TTL 60 ; 1 minute
dns                A    10.4.7.11
harbor             A    10.4.7.200
k8s-yaml           A    10.4.7.200
traefik            A    10.4.7.10
dashboard          A    10.4.7.10
zk1                A    10.4.7.11
zk2                A    10.4.7.12
zk3                A    10.4.7.21
jenkins            A    10.4.7.10
dubbo-monitor      A    10.4.7.10
demo               A    10.4.7.10

[root@hdss7-11 ~]# systemctl restart named
[root@hdss7-11 ~]# dig -t A demo.od.com @10.4.7.11 +short
10.4.7.10
 

4.4、 应用资源配置清单

[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-consumer/deployment.yaml
deployment.extensions/dubbo-demo-consumer created
[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-consumer/service.yaml
service/dubbo-demo-consumer created
[root@hdss7-21 ~]# kubectl apply -f http://k8s-yaml.od.com/dubbo-demo-consumer/ingress.yaml
ingress.extensions/dubbo-demo-consumer created


4.4、 查看状态

4.5、 查看dubbo-monitor

如果遇到访问dubbo-monitor.od.com后出现bad gateway问题,可能是重启电脑了,导致zoopkeeper没启动。

解决方案:把启动脚本写到开机启动脚本,然后手动启动zoopkeeper,杀死已经挂掉的pod

访问dubbo-monitor.od.com,查看Application,发现dubbo-demo-consumer已经注册到注册中心。而且monitor会区分是消费者还是提供者

​​​​​​​

点击dubbo-demo-consumer 的 Consumers

dubbo-demo-consumer去注册中心(zk)中,申请一个订阅,订阅什么?订阅了一个com.od.dubbotest.api.HelloService?接口。至此访问dubbo-demo-consumer这个web项目的Hello网页,后台dubbo-demo-consumer带着访问Hello网页的url去请求dubbo-demo-service​​​​​​​的HelloService接口,最后把执行后结果反给dubbo-demo-consumer网页​​​​​​​

4.6访问消费者的web项目的Hello网页

http://demo.od.com/hello?name=wewe

4.7、讲解此sprint boot源代码

其中消费者调用的提供者的hello方法。所以网页输入hello附带参数就会反回hello wewe

System.out.println("HelloAction接收到请求:"+name);  # 我请求(这是Dubbo 消费者端)网页,被
HelloAction接收到请求,并取到输入网页的参数name(wewe)

String str="<h1>这是Dubbo 消费者端(springboot)</h1>";  # 先打印“这是Dubbo 消费者端(springboot)”

System.out.println("HelloService返回到结果:"+str);  # 然后调用本地的helloService.hello(name)
方法。代码其实不知道,他调用的是通过注册中心的提供者的helloService.hello接口。代码调
用注册中心的提供者的helloService.hello接口,就跟调用本地得我一样。跟本没无任何区别。

消费者调用本地的hello方法,其实本地跟本没有hello方法,而是调用提供者声明的hello方法。但是消费者以为就是调用本地方法一样

Dubbo 这种机制有什么好处? Dubbo 典型的无状态服务,假如做促销活动,而前台是可以支撑住的,但是后台有大量的定单等,导致后台资源很卡顿,这个时候只需要对提供者做扩容,消费者不动,而扩容只需要点点dashboard就行。而且前端客户根本没有任何感觉。​​​​​​​

Logo

开源、云原生的融合云平台

更多推荐