Docker下的Nacos环境开发

Stella981
• 阅读 525

本文是《Docker下,两分钟极速体验Nacos》的续篇,前文我们极速体验了Nacos注册中心、服务提供者、服务消费者,这些应用都对应着不同的Docker容器,今天就来细说这些Docker容器的镜像。

回顾上一章的业务流程

先来回顾一下上一章,整个Docker环境中有哪些容器,提供了什么服务,如下图,请顺着橙色提示框的数字顺序来看请整个流程::
Docker下的Nacos环境开发

系列文章链接

下面是《Spring Cloud Alibaba实战系列》的所有文章地址:

  1. 《Docker下,两分钟极速体验Nacos》
  2. 《Docker下的Nacos环境开发》
  3. 《Docker下,两分钟极速体验Nacos配置中心》
  4. 《Docker下Nacos配置应用开发》

Nacos环境背后对应的Docker技术

在Docker下搭建一个包含Nacos注册中心、服务提供者、服务消费者的环境,总的来说需要做下面这些事情:

  1. 制作Nacos镜像;
  2. 制作服务提供者镜像;
  3. 制作服务消费者镜像;
  4. 制作docker-compose.yml文件,将容器编排在一起,然后一次性启动;
    接下来我们逐个开发上面提到的内容;

源码下载

如果您不打算写代码,也可以从GitHub上下载本次实战的源码,地址和链接信息如下表所示:

名称

链接

备注

项目主页

https://github.com/zq2599/blog\_demos

该项目在GitHub上的主页

git仓库地址(https)

https://github.com/zq2599/blog\_demos.git

该项目源码的仓库地址,https协议

git仓库地址(ssh)

git@github.com:zq2599/blog_demos.git

该项目源码的仓库地址,ssh协议

这个git项目中有多个文件夹,本章的应用在nacosdemo文件夹下,如下图所示:
Docker下的Nacos环境开发

制作Nacos镜像

对Nacos镜像的功能要求有以下三点:

  1. 包含Nacos server应用;

  2. 暴露web管理服务的端口;

  3. 容器启动时,Nacos服务能够自动启动;

    为了满足以上要求,除了编写Dockerfile文件,还要编写docker-entrypoint.sh文件,在容器创建时执行该文件用于启动Nacos服务;

首先是Dockerfile文件,该文件用于制作Nacos镜像:

# Docker image for Anaconda3-2019.03
# VERSION 0.0.1
# Author: bolingcavalry

### 基础镜像,使用alpine操作系统,openjkd使用8u201
FROM openjdk:8u201-jdk-alpine3.9

#作者
MAINTAINER BolingCavalry <zq2599@gmail.com>

#系统编码
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
#path
ENV PATH /opt/conda/bin:$PATH

#安装必要的软件
#RUN apt-get update --fix-missing && apt-get install -y wget
RUN apk update && apk add wget

#下载下来的压缩文件名称
ENV NACOS_FILE_NAME nacos-server-1.1.0.tar.gz

#把启动时用到的文件准备好
COPY ./docker-entrypoint.sh /docker-entrypoint.sh

#解压后的文件夹名称
ENV NACOS_FOLDER_NAME nacos

RUN wget https://github.com/alibaba/nacos/releases/download/1.1.0/nacos-server-1.1.0.tar.gz -O ~/$NACOS_FILE_NAME && \
    tar -zxf ~/$NACOS_FILE_NAME -C ~/ && \
    rm ~/$NACOS_FILE_NAME && \
    chmod a+x /docker-entrypoint.sh

ENTRYPOINT ["/docker-entrypoint.sh"]

EXPOSE 8848

从Dockerfile内容中可见,先去nacos的github下载安装包,然后解压,再复制docker-enrypoint.sh到镜像中,最后将nacos的8848端口暴露出来;
再来看看docker-enrypoint.sh文件的内容,该文件在容器启动时会被执行,内容很简单,就是进入nacos的bin目录,执行启动文件,再将start.out输出到控制台:

#!/bin/sh

echo "Starting nacos"n && \
     cd ~/nacos/bin && \
     ./startup.sh -m standalone && \
     cd ../logs && \
     tail -f start.out 

有两个重要信息需要注意:

  1. nacos的官方参考启动命令是./startup.sh -m standalone,这个命令会将jvm的输出重定向到start.out文件,也就是说nacos的JVM进程是在后台运行的,不会占用控制台(相比之下,spring boot应用使用java -jar启动时会占用控制台),对于docker来说,容器内的进程如果不占用控制台,docker就认为该容器已经结束工作,就会停止该容器,所以,为了避免nacos在docker刚刚启动就退出,需要用tail -f start.out来占领控制台;
  2. 用tail -f start.out来占领控制台可以避免容器刚刚启动就退出,但也有个弊端,就是容器中有了多个进程,并且nacos进程的PID不是1,所以在执行docker stop命令时,结束进程的信号量不会到nacos进程,而是去了PID等于1的进程,所以nacos进程不会立即退出,只能等到30秒后被强制kill,这个问题最好的解法是修改nacos的startup.sh,让nacos进程始终保持在控制台,不要重定向到后台,但这样就导致Dockerfile不好处理了,每次下载和解压了nacos安装包后,都要用本地的startup.sh去替换原有的,这样做的话,如果nacos升级版本,这边本地的startup.sh也要随之更新,很是麻烦…

构建镜像

  1. Dockerfile和docker-enrypoint.sh文件准备好之后放在同一个目录,执行以下命令构建镜像:

    docker build -t bolingcavalry/nacossimpleprovider:1.0-SNAPSHOT

  2. 如果您在hub.docker.com已经注册,可以执行以下命令将本地镜像上传到 hub.docker.com ,这样任何人都可以下载使用该镜像了:

    docker push bolingcavalry/nacossimpleprovider:1.0-SNAPSHOT

Nacos镜像的制作已经完成,接下来制作一个java应用的镜像:服务提供者;

java应用的父工程

接下来要开发的simple-provider和simple-consumer两个应用都是java应用,为了管理方便,做一个基于maven的父工程,再将simple-provider和simple-consumer以module的形式加入到这个父工程中;

  1. 基于maven创建父工程,名为nacosdemo,其pom.xml内容如下:

    4.0.0 simpleconsumer simpleprovider org.springframework.boot spring-boot-starter-parent 2.0.5.RELEASE com.bolingcavalry nacosdemo pom 1.0-SNAPSHOT <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring.boot.version>2.0.5.RELEASE</spring.boot.version> <spring.cloud.version>Finchley.SR1</spring.cloud.version> <spring.cloud.alibaba.version>0.2.2.RELEASE</spring.cloud.alibaba.version> org.springframework.cloud spring-cloud-dependencies ${spring.cloud.version} pom import org.springframework.cloud spring-cloud-alibaba-dependencies ${spring.cloud.alibaba.version} pom import org.apache.maven.plugins maven-compiler-plugin ${java.version} ${java.version} ${project.build.sourceEncoding}

可见这是个普通的父工程,里面对spring cloud和spring cloud alibaba的版本做了控制,避免子工程还要各种指定版本的繁琐操作;

制作服务提供者镜像

simple-provider是个java web应用,使用了spring cloud alibaba的依赖库之后可以使用Nacos的注册发现服务,整个工程的开发步骤如下:

  1. 基于maven创建工程,其pom.xml内容如下:

    nacosdemo com.bolingcavalry 1.0-SNAPSHOT 4.0.0 simpleprovider org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.boot spring-boot-maven-plugin com.google.cloud.tools jib-maven-plugin 1.3.0 openjdk:8u201-jdk-alpine3.9 bolingcavalry/nacos${project.artifactId}:${project.version} -Xms1g -Xmx1g

上述内容有两点需要注意:
a. 依赖spring-cloud-starter-alibaba-nacos-discovery,这样可以用上spring cloud nacos的服务;
b. 使用了maven插件jib-maven-plugin,用于将应用构建成docker镜像,此插件相关的详情请参考《Docker与Jib(maven插件版)实战》
2. 配置文件application.properties,配置应用名称和nacos地址,注意这里nacos地址配置的是nacoshost,对应的是后面docker-compose.yml中的link参数:

spring.application.name=simple-provider
spring.cloud.nacos.discovery.server-addr=nacoshost:8848
  1. 应用启动类SimpleProviderApplication ,配置了注解EnableDiscoveryClient,用于启动注册发现服务:

    package simpleprovider;

    import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

    @EnableDiscoveryClient @SpringBootApplication public class SimpleProviderApplication {

    public static void main(String[] args) {
    
    
    
        SpringApplication.run(SimpleProviderApplication.class, args);
    }
    

    }

  2. 增加一个提供http服务的controller类ProviderController:

    package simpleprovider.controller;

    import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;

    import java.text.SimpleDateFormat; import java.util.Date;

    /**

    • @Description: 提供web服务的controller
    • @author: willzhao E-mail: zq2599@gmail.com
    • @date: 2019/7/28 11:08

    */ @RestController public class ProviderController {

    @RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
    public String hello(@PathVariable("name") String name){
    
    
    
        return "hello " + name + ", " + new SimpleDateFormat("yyyy-mm-dd  HH:mm:ss").format(new Date());
    }
    

    }

  3. 以上就是simple-provider的所有源码了,在pom.xml所在目录执行以下命令,即可构建docker镜像,存入本地仓库:

    mvn compile jib:dockerBuild

制作服务消费者镜像

simple-consumer是个java web应用,启动后对外提供http服务,响应的时候,通过nacos取得simple-provider的地址,然后向simple-provider发请求,将响应返回给浏览器:

  1. 基于maven创建工程,其pom.xml内容如下:

    nacosdemo com.bolingcavalry 1.0-SNAPSHOT 4.0.0 simpleconsumer org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.boot spring-boot-maven-plugin com.google.cloud.tools jib-maven-plugin 1.3.0 openjdk:8u201-jdk-alpine3.9 bolingcavalry/nacos${project.artifactId}:${project.version} -Xms1g -Xmx1g 8080

  2. 配置文件application.properties,配置应用名称和nacos地址,注意这里nacos地址配置的是nacoshost,对应的是后面docker-compose.yml中的link参数:

    spring.application.name=simple-consumer spring.cloud.nacos.discovery.server-addr=nacoshost:8848

  3. 应用启动类SimpleConsumerApplication,配置了注解EnableDiscoveryClient,用于启动注册发现服务:

    package com.bolingcavalry.simpleconsumer;

    import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

    @EnableDiscoveryClient @SpringBootApplication public class SimpleConsumerApplication {

    public static void main(String[] args) {
    
    
    
        SpringApplication.run(SimpleConsumerApplication.class, args);
    }
    

    }

  4. 增加一个提供http服务的controller类ConsumerController,通过LoadBalancerClient取得simple-provider的服务地址,然后发请求过去 :

    package com.bolingcavalry.simpleconsumer.controller;

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;

    import java.text.SimpleDateFormat; import java.util.Date;

    /**

    • @Description: 提供web服务的controller
    • @author: willzhao E-mail: zq2599@gmail.com
    • @date: 2019/7/28 11:08

    */ @RestController public class ConsumerController {

    @Autowired
    LoadBalancerClient loadBalancerClient;
    
    @RequestMapping("/test")
    public String test(){
    
    
    
        //根据应用名称取得实例对象
        ServiceInstance serviceInstance = loadBalancerClient.choose("simple-provider");
        //根据实例对象取得地址
        String uri = serviceInstance.getUri().toString();
        String result = new RestTemplate().getForObject(uri + "/hello/bolingcavalry", String.class);
        return "provider uri : " + uri + "<br>" + "response :" + result;
    }
    

    }

  5. 以上就是simple-consumer的所有源码了,在pom.xml所在目录执行以下命令,即可构建docker镜像,存入本地仓库:

    mvn compile jib:dockerBuild

编写docker-compose.yml

三个镜像都准备好了,接下来是做容器编排,docker-compose.yml内容如下:

version: '2'
services:
  nacos:
    image: bolingcavalry/nacosserver:0.0.1
    container_name: nacos
    restart: unless-stopped
    ports:
      - '8848:8848'
  provider: 
    image: bolingcavalry/nacossimpleprovider:1.0-SNAPSHOT
    links:
      - nacos:nacoshost
    depends_on:
      - nacos
    restart: unless-stopped
  consumer: 
    image: bolingcavalry/nacossimpleconsumer:1.0-SNAPSHOT
    links:
      - nacos:nacoshost
    container_name: consumer
    depends_on:
      - nacos
    ports:
      - '8080:8080'
    restart: unless-stopped

上述编排文件,有几点需要注意:
a. 可以用container_name设置容器的名字,但是不要给provider的容器设置名字,因为按照规划provider会启动多个容器,指定名字会导致第二个容器启动时报名字冲突的错误;
b. provider和consumer通过depends_on参数,将自己的启动时间放在了nacos后面;
c. links的作用是将nacos的IP地址,写入provider和consumer的/etc/hosts文件中,这样这两个容器内容的应用可以通过nacoshost来访问nacos了;

启动多个容器

在docker-compose.yml所在目录执行以下命令,即可启动所有容器,并且provider容器会启动6个:

docker-compose up --scale provider=6 -d

至此,整个nacos的docker环境搭建过程已经回顾完毕,在您搭建自己的容器环境时,希望本文能给您一些参考;

欢迎关注我的公众号:程序员欣宸

Docker下的Nacos环境开发

本文同步分享在 博客“程序员欣宸”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这