Docker de entrada a salida (3): demasiados contenedores, orquestación optimizada

    En los dos artículos anteriores, explicamos el contenedor SpringBoot basado en la implementación de la ventana acoplable. Si no hay una base relevante antes de leer este artículo, puede revisar el tutorial anterior.

Docker de entrada a foso

Docker de la entrada a la trampa (2): compile microservicios SpringBoot basados ​​en Docker

    No sé si se encontró con este escenario la primera vez que utilizó Docker. Cada vez que implementa un microservicio, debe ejecutar comandos como Docker run xxx, Docker kill xxx para operar el contenedor. Suponiendo que un sistema se basa en varios contenedores de la ventana acoplable, ¿la implementación de cada contenedor de la ventana acoplable necesita escribir comandos manualmente para iniciarse y apagarse? Hacerlo aumentará la carga de trabajo de desarrollo del personal de operación y mantenimiento y también es propenso a errores.

Tecnología de orquestación de Docker Compose

En el artículo anterior, explicamos el desarrollo de la tecnología de contenedorización de Docker, pero a medida que tenemos más y más Docker , la gestión de contenedores también es particularmente problemática, por lo que nació la tecnología Docker Compose .

La tecnología Docker Compose es una herramienta de Docker que define y ejecuta una serie de aplicaciones complejas a través de un archivo e inicia varios contenedores a través de un archivo Docker-compose. Hay muchos casos reales de Docker-compose en Internet, pero se omiten algunos detalles. Entonces, a continuación, lo llevaré paso a paso para aprender a componer Docker desde lo más superficial a lo más profundo a través de un caso simple.

Basado en Docker Compose para empaquetar e integrar aplicaciones de microservicio SpringBoot

Creemos un proyecto básico de microservicio SpringBoot como de costumbre. Primero, echemos un vistazo a la estructura del proyecto de la versión básica:

El primero es el contenido de configuración de nuestro archivo pom:

 

<?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>

    <groupId>com.sise.idea</groupId>
    <artifactId>springboot-docker</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring-boot-docker</name>
    <url>http://maven.apache.org</url>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>springboot-docker</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Luego está el código de contenido del programa Java. Hay clases de aplicación y controlador convencionales. El código es el siguiente:

Solicitud de clase de inicio

package com.sise.docker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author idea
 * @data 2019/11/20
 */
@SpringBootApplication
public class Application {

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

Controlador DockerController

package com.sise.docker.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author idea
 * @data 2019/11/20
 */
@RestController
@RequestMapping(value = "/docker")
public class DockerController {


    @GetMapping(value = "/test")
    public String test(){
        System.out.println("=========docker test=========");
        return "this is docker test";
    }
}

archivo de configuración yml:

server:
  port: 7089

El siguiente es el archivo de configuración que se usa cuando se empaqueta docker-compose. El método utilizado aquí suele ser escribir un archivo docker para el contenedor de la ventana acoplable necesario, y luego empaquetarlo y administrarlo mediante Docker Compose. Suponiendo que nuestros microservicios necesitan hacer referencia a aplicaciones como MySQL y MongoDB, la arquitectura general se muestra en la siguiente figura:

Así que comencemos con un contenedor simple y veamos cómo administrar SpringBoot con Docker Compose. A continuación se muestra un Dockerfile que empaqueta SpringBoot en el contenedor Docker:

 

#需要依赖的其他镜像
FROM openjdk:8-jdk-alpine
# Spring Boot应用程序为Tomcat创建的默认工作目录。作用是在你的主机”/var/lib/docker”目录下创建一个临时的文件,并且链接到容器中#的”/tmp”目录。
VOLUME /tmp

#是指将原先的src文件 添加到我们需要打包的镜像里面
ADD target/springboot-docker.jar app.jar

#设置镜像的时区,避免出现8小时的误差
ENV TZ=Asia/Shanghai

#容器暴露的端口号 和SpringBoot的yml文件暴露的端口号要一致
EXPOSE 7089

#输入的启动参数内容 下边这段内容相当于运行了java -Xms256m -Xmx512m -jar app.jar 
ENTRYPOINT ["java","-Xms256m","-Xmx512m","-jar","app.jar"]

Luego está el enlace para agregar el archivo docker-compose.yml. A continuación se muestra el contenido del script:

#docker引擎对应所支持的docker-compose文本格式
version: '3'
services:

  #服务的名称
  springboot-docker:
    build:
      context: .
      # 构建这个容器时所需要使用的dockerfile文件
      dockerfile: springboot-dockerfile
    ports:
      # docker容器和宿主机之间的端口映射
      - "7089:7089"

El archivo de configuración docker-compose.ym tiene reglas especiales. Por lo general, primero definimos el número de versión y luego enumeramos una serie de servicios relacionados con el contenedor.

A continuación, empaquete este servicio de la ventana acoplable e impleméntelo en el servidor Linux correspondiente. Aquí utilizo un servidor comprado en Alibaba Cloud para demostrarlo.

En la actualidad, el archivo no se ha empaquetado, por lo que no hay un directorio de destino, por lo que cuando se crea el archivo dockerfile, no tendrá éxito, por lo que primero debe empaquetar mvn:

 

mvn package

Lo siguiente es la entrada del comando Docker-Compose:

[root@izwz9ic9ggky8kub9x1ptuz springboot-docker]# docker-compose up -d
Starting springboot-docker_springboot-docker_1 ... done
[root@izwz9ic9ggky8kub9x1ptuz springboot-docker]# 

Verá que el comando ingresado esta vez es algo diferente del comando docker mencionado en el tutorial anterior. Se convierte en el comando docker-compose. Este comando está diseñado específicamente para el archivo de composición de Docker, agregando un parámetro -d para Indica que el contenedor se está ejecutando en segundo plano. Dado que el conocimiento en nuestro archivo docker-compose escribe el empaquetado del contenedor SpringBoot, solo se mostrará un contenedor docker al iniciar.

Para verificar si el comando docker-compose tiene efecto, podemos verificarlo a través del comando docker - compose ps .

Aquí usamos el   comando docker logs [container id] para ingresar al contenedor y ver la impresión del registro:

docker logs ad83c82b014d

 

 

Finalmente, veremos la respuesta relevante a través de la interfaz escrita antes de la solicitud:  

 

Se ha construido la versión básica del caso de composición SpringBoot + Docker. Recuerda la imagen que dibujé al principio:

 

Por lo general, en el desarrollo real, el contenedor de la ventana acoplable al que nos enfrentamos no es tan simple y puede depender de varios contenedores, entonces, ¿cómo escribir el archivo de composición de la ventana acoplable en este momento?

A continuación agregamos la dependencia de MySQL y MongoDB al proyecto SpringBoot original . Para facilitar la simulación del siguiente escenario, aquí agregamos dos clases de entidad:

Clase de usuario

package com.sise.docker.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author idea
 * @data 2019/11/23
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {

    private Integer id;

    private String username;
}

Categoría de automóvil:

package com.sise.docker.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;

/**
 * @author idea
 * @data 2019/11/23
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {

    @Id
    private Integer id;

    private String number;
}

Aumente el contenido de dependencia de pom para mongodb y mysql

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>

Escribe la capa de dao relevante:

package com.sise.docker.dao;

import com.sise.docker.domain.Car;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

/**
 * @author idea
 * @data 2019/11/23
 */
@Repository
public interface CarDao extends MongoRepository<Car, Integer> {
}

 

package com.sise.docker.dao;

import com.sise.docker.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @author idea
 * @data 2019/11/23
 */
@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    public void insert() {
        String time = String.valueOf(System.currentTimeMillis());
        String sql = "insert into t_user (username) values ('idea-" + time + "')";
        jdbcTemplate.update(sql);
        System.out.println("==========执行插入语句==========");
    }

    class UserMapper implements RowMapper<User> {

        @Override
        public User mapRow(ResultSet resultSet, int i) throws SQLException {
            User unitPO = new User();
            unitPO.setId(resultSet.getInt("id"));
            unitPO.setUsername(resultSet.getString("username"));
            return unitPO;
        }
    }
}

Agregue la entrada de función relevante en el controlador:

package com.sise.docker.controller;

import com.sise.docker.dao.CarDao;
import com.sise.docker.dao.UserDao;
import com.sise.docker.domain.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;

/**
 * @author idea
 * @data 2019/11/20
 */
@RestController
@RequestMapping(value = "/docker")
public class DockerController {

    @Autowired
    private UserDao userDao;
    @Autowired
    private CarDao carDao;

    @GetMapping(value = "/insert-mongodb")
    public String insertMongoDB() {
        Car car = new Car();
        car.setId(new Random().nextInt(15000000));
        String number = String.valueOf(System.currentTimeMillis());
        car.setNumber(number);
        carDao.save(car);
        return "this is insert-mongodb";
    }

    @GetMapping(value = "/insert-mysql")
    public String insertMySQL() {
        userDao.insert();
        return "this is insert-mysql";
    }

    @GetMapping(value = "/test2")
    public String test() {
        System.out.println("=========docker test222=========");
        return "this is docker test";
    }
}

Agregue el contenido correspondiente al archivo docker-compose.yml original, principalmente para aumentar los módulos dependientes para mongodb y mysql,

#docker引擎对应所支持的docker-compose文本格式
version: '3'
services:

  #服务的名称
  springboot-docker:
    container_name: docker-springboot
    build:
      context: .
      dockerfile: springboot-dockerfile
    ports:
      - "7089:7089"

    depends_on:
      - mongodb


  mongodb:
    #容器的名称
    container_name: docker-mongodb
    image: daocloud.io/library/mongo:latest
    ports:
      - "27017:27017"

  mysql:
    #镜像的版本
    image: mysql:5.7
    container_name: docker-mysql
    ports:
      - 3309:3306
    environment:
       MYSQL_DATABASE: test
       MYSQL_ROOT_PASSWORD: root
       MYSQL_ROOT_USER: root
       MYSQL_ROOT_HOST: '%'

Aquí trato de distinguir el archivo application.yml a través de diferentes perfiles:

 

En respuesta a la pregunta de un lector en el artículo anterior, hay una forma de pensar sobre la designación de diferentes configuraciones en diferentes entornos. Springboot aún mantiene el perfil original para identificar la configuración de diferentes entornos. La configuración leída después de un paquete específico se puede leer a través de springboot- El parámetro ENTRYPOINT de este archivo dockerfile se especifica, por ejemplo, el siguiente formato:

 

FROM openjdk:8-jdk-alpine

VOLUME /tmp

ADD target/springboot-docker.jar springboot-docker.jar

#设置镜像的时区,避免出现8小时的误差
ENV TZ=Asia/Shanghai

EXPOSE 7089
#这里可以通过-D参数在对jar打包运行的时候指定需要读取的配置问题
ENTRYPOINT ["java","-Xms256m","-Xmx512m","-Dspring.profiles.active=prod","-jar","springboot-docker.jar"]

El último es el contenido de nuestro archivo de configuración yml. Debido a la dependencia del contenedor docker de la clase de configuración, el método de escritura para yml ya no es acceder a la base de datos correspondiente a través de ip, sino lograr el objetivo a través del mapeo del nombre del servicio.

application-prod.yml

server:
  port: 7089

spring:
    data:
      mongodb:
        uri: mongodb://mongodb:27017
        database: test

    datasource:
             driver-class-name: com.mysql.jdbc.Driver
             url: jdbc:mysql://mysql:3306/test?useUnicode=true&amp;characterEncoding=UTF-8
             username: root
             password: root

Cuando se clasifican el código y los archivos relevantes, el código se envía al servidor para empaquetarlo.

mvn package

Entonces podemos comenzar a docker-compose.

Hay un pequeño pozo al que prestar atención. Dado que hemos empaquetado un contenedor springboot separado antes, daremos prioridad al uso del contenedor existente en lugar de recrear el contenedor al ejecutar el comando docker-compose up.


En este momento, debe eliminar manualmente la imagen de la imagen original antes de empaquetar:

[root@izwz9ic9ggky8kub9x1ptuz springboot-docker]# docker images
REPOSITORY                                           TAG                 IMAGE ID            CREATED             SIZE
springboot-docker                  latest              86f32bd9257f        4 hours ago         128MB
<none>                                               <none>              411616c3d7f7        2 days ago          679MB
<none>                                               <none>              77044e3ad9c2        2 days ago          679MB
<none>                                               <none>              5d9328dd1aca        2 days ago          679MB
springbootmongodocker_springappserver                latest              36237acf08e1        3 days ago          695MB

Comando para eliminar espejo:

docker rmi 【镜像id】


En este punto, puede volver a empaquetar la instrucción docker-compose:

docker-compose up

 

Después del inicio, puede utilizar algunas instrucciones que vienen con docker-compose para operar. Algunas de las instrucciones más utilizadas se resumen a continuación:

 

docker-compose [Comando]

 

Commands:
  build              构建或重建服务
  bundle             从compose配置文件中产生一个docker绑定
  config             验证并查看compose配置文件
  create             创建服务
  down               停止并移除容器、网络、镜像和数据卷
  events             从容器中接收实时的事件
  exec               在一个运行中的容器上执行一个命令
  help               获取命令的帮助信息
  images             列出所有镜像
  kill               通过发送SIGKILL信号来停止指定服务的容器
  logs               从容器中查看服务日志输出
  pause              暂停服务
  port               打印绑定的公共端口
  ps                 列出所有运行中的容器
  pull               拉取并下载指定服务镜像
  push               Push service images
  restart            重启YAML文件中定义的服务
  rm                 删除指定已经停止服务的容器
  run                在一个服务上执行一条命令
  scale              设置指定服务运行容器的个数
  start              在容器中启动指定服务
  stop               停止已运行的服务
  top                显示各个服务容器内运行的进程
  unpause            恢复容器服务
  up                 创建并启动容器
  version            显示Docker-Compose版本信息

Finalmente, verifique la interfaz correspondiente:

He subido el código completo correspondiente a la dirección del albergue y los amigos que lo necesitan pueden descargarlo.

Dirección de código: https://gitee.com/IdeaHome_admin/wfw

Después de la práctica, es posible que sienta que con docker-compose es particularmente fácil administrar varios contenedores de la ventana acoplable.

Pero a menudo no es tan simple en la realidad. Docker-compose tiene un inconveniente, es decir , no puede administrar contenedores de docker entre máquinas .

Por lo tanto, con el desarrollo de la tecnología, una tecnología llamada Kubernetes ha aparecido lentamente detrás . Kubernetes (comúnmente conocido como k8s) es un código abierto que se utiliza para administrar aplicaciones en contenedores en múltiples hosts en la plataforma en la nube. El objetivo de Kubernetes es hacer que la implementación de aplicaciones en contenedores sea simple y eficiente. Kubernetes proporciona implementación y planificación de aplicaciones , Actualizar y mantener un mecanismo.

Las tecnologías como Kubernetes son difíciles de iniciar para Xiaobai, y puedo tomarme el tiempo para escribir un artículo introductorio de k8s adecuado para que Xiaobai lo lea.

 

 

 

Supongo que te gusta

Origin blog.csdn.net/bj_chengrong/article/details/103234077
Recomendado
Clasificación