前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker下的Nacos环境开发

Docker下的Nacos环境开发

作者头像
程序员欣宸
发布2019-08-14 11:14:15
3.1K0
发布2019-08-14 11:14:15
举报
文章被收录于专栏:实战docker

版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

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

回顾上一章的业务流程

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

Nacos环境背后对应的Docker技术

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

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

源码下载

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

名称

链接

备注

项目主页

该项目在GitHub上的主页

git仓库地址(https)

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

git仓库地址(ssh)

git@github.com:zq2599/blog_demos.git

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

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

制作Nacos镜像

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

  1. 包含Nacos server应用;
  2. 暴露web管理服务的端口;
  3. 容器启动时,Nacos服务能够自动启动;

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

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

代码语言:javascript
复制
# 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输出到控制台:

代码语言:javascript
复制
#!/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文件准备好之后放在同一个目录,执行以下命令构建镜像:
代码语言:javascript
复制
docker build -t bolingcavalry/nacossimpleprovider:1.0-SNAPSHOT
  1. 如果您在hub.docker.com已经注册,可以执行以下命令将本地镜像上传到 hub.docker.com ,这样任何人都可以下载使用该镜像了:
代码语言:javascript
复制
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内容如下:
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <modules>
        <module>simpleconsumer</module>
        <module>simpleprovider</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.bolingcavalry</groupId>
    <artifactId>nacosdemo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <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>
    </properties>

    <!-- 依赖声明 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!--编译管理 jdk版本和字符集编码-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

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

制作服务提供者镜像

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

  1. 基于maven创建工程,其pom.xml内容如下:
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>nacosdemo</artifactId>
        <groupId>com.bolingcavalry</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>simpleprovider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--使用jib插件-->
            <plugin>
                <groupId>com.google.cloud.tools</groupId>
                <artifactId>jib-maven-plugin</artifactId>
                <version>1.3.0</version>
                <configuration>
                    <!--from节点用来设置镜像的基础镜像,相当于Docerkfile中的FROM关键字-->
                    <from>
                        <!--使用openjdk官方镜像,tag是8u201-jdk-alpine3.9,表示镜像的操作系统是alpine3.9,装好了jdk8u201-->
                        <image>openjdk:8u201-jdk-alpine3.9</image>
                    </from>
                    <to>
                        <!--镜像名称和tag,使用了mvn内置变量${project.artifactId}和${project.version}-->
                        <image>bolingcavalry/nacos${project.artifactId}:${project.version}</image>
                    </to>
                    <!--容器相关的属性-->
                    <container>
                        <!--jvm内存参数-->
                        <jvmFlags>
                            <jvmFlag>-Xms1g</jvmFlag>
                            <jvmFlag>-Xmx1g</jvmFlag>
                        </jvmFlags>
                    </container>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

上述内容有两点需要注意:

a. 依赖spring-cloud-starter-alibaba-nacos-discovery,这样可以用上spring cloud nacos的服务;

b. 使用了maven插件jib-maven-plugin,用于将应用构建成docker镜像,此插件相关的详情请参考《Docker与Jib(maven插件版)实战》

  1. 配置文件application.properties,配置应用名称和nacos地址,注意这里nacos地址配置的是nacoshost,对应的是后面docker-compose.yml中的link参数:
代码语言:javascript
复制
spring.application.name=simple-provider
spring.cloud.nacos.discovery.server-addr=nacoshost:8848
  1. 应用启动类SimpleProviderApplication ,配置了注解EnableDiscoveryClient,用于启动注册发现服务:
代码语言:javascript
复制
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);
    }
}
  1. 增加一个提供http服务的controller类ProviderController:
代码语言:javascript
复制
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());
    }
}
  1. 以上就是simple-provider的所有源码了,在pom.xml所在目录执行以下命令,即可构建docker镜像,存入本地仓库:
代码语言:javascript
复制
mvn compile jib:build

制作服务消费者镜像

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

  1. 基于maven创建工程,其pom.xml内容如下:
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>nacosdemo</artifactId>
        <groupId>com.bolingcavalry</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>simpleconsumer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--使用jib插件-->
            <plugin>
                <groupId>com.google.cloud.tools</groupId>
                <artifactId>jib-maven-plugin</artifactId>
                <version>1.3.0</version>
                <configuration>
                    <!--from节点用来设置镜像的基础镜像,相当于Docerkfile中的FROM关键字-->
                    <from>
                        <!--使用openjdk官方镜像,tag是8u201-jdk-alpine3.9,表示镜像的操作系统是alpine3.9,装好了jdk8u201-->
                        <image>openjdk:8u201-jdk-alpine3.9</image>
                    </from>
                    <to>
                        <!--镜像名称和tag,使用了mvn内置变量${project.artifactId}和${project.version}-->
                        <image>bolingcavalry/nacos${project.artifactId}:${project.version}</image>
                    </to>
                    <!--容器相关的属性-->
                    <container>
                        <!--jvm内存参数-->
                        <jvmFlags>
                            <jvmFlag>-Xms1g</jvmFlag>
                            <jvmFlag>-Xmx1g</jvmFlag>
                        </jvmFlags>
                        <!--要暴露的端口-->
                        <ports>
                            <port>8080</port>
                        </ports>
                    </container>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  1. 配置文件application.properties,配置应用名称和nacos地址,注意这里nacos地址配置的是nacoshost,对应的是后面docker-compose.yml中的link参数:
代码语言:javascript
复制
spring.application.name=simple-consumer
spring.cloud.nacos.discovery.server-addr=nacoshost:8848
  1. 应用启动类SimpleConsumerApplication,配置了注解EnableDiscoveryClient,用于启动注册发现服务:
代码语言:javascript
复制
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);
    }
}
  1. 增加一个提供http服务的controller类ConsumerController,通过LoadBalancerClient取得simple-provider的服务地址,然后发请求过去 :
代码语言:javascript
复制
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;
    }
}
  1. 以上就是simple-consumer的所有源码了,在pom.xml所在目录执行以下命令,即可构建docker镜像,存入本地仓库:
代码语言:javascript
复制
mvn compile jib:build

编写docker-compose.yml

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

代码语言:javascript
复制
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个:

代码语言:javascript
复制
docker-compose up --scale provider=6 -d

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年08月04日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 回顾上一章的业务流程
  • Nacos环境背后对应的Docker技术
  • 源码下载
  • 制作Nacos镜像
  • 构建镜像
  • java应用的父工程
  • 制作服务提供者镜像
  • 制作服务消费者镜像
  • 编写docker-compose.yml
  • 启动多个容器
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档