Docker从入门到掉坑(三):容器太多,编排优化

    前边的两篇文章里面,我们讲解了基于docker来部署基础的SpringBoot容器,如果阅读本文之前没有相关基础的话,可以回看之前的教程。

Docker 从入门到掉坑

Docker从入门到掉坑(二):基于Docker构建SpringBoot微服务

    不知道大家在初次使用docker的时候是否有遇到这种场景,每次部署微服务都是需要执行docker run xxx,docker kill xxx 等命令来操作容器。假设说一个系统中依赖了多个docker容器,那么对于每个docker容器的部署岂不是都需要手动编写命令来启动和关闭,这样做就会增加运维人员的开发工作量,同时也容易出错。

Docker Compose 编排技术

在前边的文章中,我们讲解了Docker容器化技术的发展,但是随着我们的Docker越来越多的时候,对于容器的管理也是特别麻烦,因此Docker Compose技术也就诞生了。

Docker Compose技术是通过一份文件来定义和运行一系列复杂应用的Docker工具,通过Docker-compose文件来启动多个容器,网上有很多关于Docker-compose的实战案例,但是都会有些细节地方有所遗漏,所以下边我将通过一个简单的案例一步步地带各位从浅入深地对Docker-compose进行学习。

基于Docker Compose来进行对SpringBoot微服务应用的打包集成

我们还是按照老样子来构建一套基础的SpringBoot微服务项目,首先我们来看看基础版本的项目结构:

首先是我们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>

然后是java程序的内容代码,这里面有常规的controller,application类,代码如下所示:

启动类Application

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);
    }
}

控制器 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";
    }
}

yml配置文件:

server:
  port: 7089

接下来便是docker-compose打包时候要用到的配置文件了。这里采用的方式通常都是针对必要的docker容器编写一份dockerfile,然后统一由Docker Compose进行打包管理,假设我们的微服务中需要引用到了MySQL,MongoDB等应用,那么整体架构如下图所示:

那么我们先从简单的单个容器入手,看看该如何对SpringBoot做Docker Compose的管理,下边是一份打包SpringBoot进入Docker容器的Dockerfile文件:

 

#需要依赖的其他镜像
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"]

接着便是加入docker-compose.yml文件的环节了,下边是脚本的内容:

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

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

docker-compose.ym配置文件有着特殊的规则,通常我们都是先定义version版本号,然后便是列举一系列与容器相关的services内容。

接下来将这份docker服务进行打包,部署到相关的linux服务器上边,这里我采用的是一台阿里云上边购买的服务器来演示。

目前该文件还没有进行打包处理,所以没有target目录,因此dockerfile文件构建的时候是不会成功的,因此需要先进行mvn的打包:

 

mvn package

接着便是进行Docker-Compose命令的输入了:

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

你会发现这次输入的命令和之前教程中提及的docker指令有些出入,变成了docker-compose 指令,这条指令是专门针对Docker compose文件所设计的,加入了一个-d的参数用于表示后台运行该容器。由于我们的docker-compose文件中知识编写了对于SpringBoot容器的打包,因此启动的时候只会显示一个docker容器。

为了验证docker-compose指令是否生效,我们可以通过docker--compose ps命令来进行验证。

这里边我们使用 docker logs [容器id] 指令可以进入容器查看日志的打印情况:

docker logs ad83c82b014d

 

 

最后我们通过请求之前写好的接口便会看到相关的响应:  

 

基础版本的SpringBoot+Docker compose案例已经搭建好了,还记得我在开头画的那张图片吗:

 

通常在实际开发中,我们所面对的docker容器并不是那么的简单,还有可能会依赖到多个容器,那么这个时候该如何来编写docker compose文件呢?

下边我们对原先的SpringBoot项目增加对于MySQLMongoDB的依赖,为了方便下边的场景模拟,这里我们增加两个实体类:

用户类

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;
}

汽车类:

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;
}

增加对于mongodb,mysql的pom依赖内容

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

编写相关的dao层:

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;
        }
    }
}

在控制器中添加相关的函数入口:

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";
    }
}

对原先的docker-compose.yml文件添加相应的内容,主要是增加对于mongodb和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: '%'

这里头我尝试将application.yml文件通过不同的profile来进行区分:

 

应上篇文章中有读者问到,不同环境不同配置的指定问题,这里有一种思路,springboot依旧保持原有的按照profile来识别不同环境的配置,具体打包之后读取的配置,可以通过springboot-dockerfile这份文件的ENTRYPOINT 参数来指定,例如下边这种格式:

 

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"]

最后便是我们的yml配置文件内容,由于配置类docker容器的依赖,所以这里面对于yml的写法不再是通过ip来访问相应的数据库了,而是需要通过service-name的映射来达成目标。

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

当相关的代码和文件都整理好了之后,将这份代码发送到服务器上进行打包。

mvn package

接着我们便可以进行docker-compose的启动了。

这里有个小坑需要注意一下,由于之前我们已经对单独的springboot容器进行过打包了,所以在执行docker-compose up指令的时候会优先使用已有的容器,而不是重新创建容器。


这个时候需要先将原先的image镜像进行手动删除,再打包操作:

[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

删除镜像的命令:

docker rmi 【镜像id】


此时再重新进行docker-compose指令的打包操作即可:

docker-compose up

 

启动之后,可以通过docker-compose自带的一些指令来进行操作,常用的一些指令我都归纳在了下边:

 

docker-compose [Command]

 

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版本信息

最后对相应的接口做检测:

相关的完整代码我已经上传到了gitee地址,如果有需要的朋友可以前往进行下载。

代码地址:https://gitee.com/IdeaHome_admin/wfw

实践完毕之后,你可能会觉得有了docker-compose之后,对于多个docker容器来进行管理显得就特别轻松了。

但是往往现实中并没有这么简单,docker-compose存在着一个弊端,那就是不能做跨机器之间的docker容器进行管理

因此随者技术的发展,后边也慢慢出现了一种叫做Kubernetes的技术。Kubernetes(俗称k8s)是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。

Kubernetes这类技术对于小白来说入门的难度较高,后边可能会抽空专门来写一篇适合小白阅读的k8s入门文章。

 

 

 

<think>好的,用户想要查找关于Docker容器使用的教程,特别是针对初学者的指南。我需要根据用户提供的引用内容来整理相关信息,并生成一个结构清晰的回答。首先,看看用户提供的引用内容。 引用[1]提到了修复Docker容器漏洞,这可能和安全相关,但用户现在需要的是使用教程,所以这个引用可能不太相关,不过可以暂时留着备用。引用[2]详细说明了Docker的端口映射,特别是如何将容器内部的端口映射到主机,这应该是使用Docker运行服务时的关键步骤,需要重点强调。引用[3]是关于volume映射的操作,具体是通过docker cp命令复制文件,这可能涉及数据持久化,这也是Docker使用中的重要部分,应该包含在教程里。引用[4]和[5]分别是关于Kubernetes和AWS EC2的指南,可能和Docker相关,但用户明确需要Docker容器的教程,所以这两个可能暂时不需要,但需要确认是否有相关内容。 用户可能需要从基础开始,比如安装、运行容器、端口映射、数据卷管理、常用命令等。根据引用[2]中的端口映射部分,应该详细解释docker run -p参数的用法。引用[3]中的volume映射也是一个重点,数据持久化对容器来说很重要,避免数据丢失。另外,用户可能还需要一些基本的命令,比如启动、停止容器,查看日志等。 需要确保回答结构清晰,分步骤讲解。可能的结构是:安装Docker -> 运行第一个容器 -> 端口映射 -> 数据卷管理 -> 常用命令 -> 学习资源。每个部分结合引用内容中的例子,比如引用[2]中的端口映射命令,引用[3]中的volume操作。 还要注意用户提到“beginner guide”,所以需要从基础开始,避免太深入的高级话题。可能需要包括一些常见问题,比如如何访问容器内的服务,如何处理数据持久化,如何查看运行中的容器等。 另外,用户提供的引用中有提到“docker run -p <host port>:<container port>”,这个需要详细说明,可能给出具体的例子,比如运行nginx并将80端口映射到主机的8080端口。数据卷部分可以结合docker cp命令,或者使用-v参数进行目录挂载。 需要检查是否有遗漏的重要点,比如Dockerfile的编写,构建镜像,但用户可能暂时只需要容器使用的基础知识,所以可能不需要深入Dockerfile,除非教程中包含这部分。但作为初学指南,可能还是需要简单提及如何获取镜像,运行容器等基本操作。 最后,生成相关问题,可能需要包括如何安装Docker优化容器性能,安全实践,多容器管理,Dockerfile使用等,结合引用中的内容,比如引用[1]的安全问题,引用[4]的K8s可能作为扩展。 现在需要组织这些内容,确保每个步骤都有对应的引用支持,并且语言简洁明了,适合初学者。</think>### Docker 容器使用入门指南 #### 1. **安装 Docker** - 访问[Docker 官网](https://www.docker.com/)下载对应操作系统的安装包。 - 安装完成后,在终端输入 `docker --version` 验证是否成功[^1]。 #### 2. **运行第一个容器** - 使用 `docker run` 命令启动容器。例如,运行一个 Nginx 服务: ```bash docker run -d --name my-nginx nginx ``` - `-d` 表示后台运行,`--name` 指定容器名称[^2]。 #### 3. **端口映射:访问容器服务** - 容器默认隔离网络,需通过**端口映射**暴露服务。例如将主机的 8080 端口映射到容器的 80 端口: ```bash docker run -d -p 8080:80 --name web-server nginx ``` - 访问 `http://localhost:8080` 即可看到 Nginx 默认页面。 #### 4. **数据卷管理:持久化容器数据** - 使用 `-v` 参数挂载主机目录到容器,避免数据丢失: ```bash docker run -d -v /host/data:/container/data --name data-container ubuntu ``` - 复制文件到容器(或反向)可使用 `docker cp`: ```bash docker cp /mnt/local-file.txt my-container:/path/in/container [^3] ``` #### 5. **常用命令** - 查看运行中的容器:`docker ps` - 停止容器:`docker stop <容器名>` - 查看容器日志:`docker logs <容器名>` - 进入容器终端:`docker exec -it <容器名> /bin/bash` #### 6. **学习资源扩展** - 官方文档:[Docker Docs](https://docs.docker.com/) - 进阶主题:Kubernetes 容器编排(参考[K8s 入门指南][^4]) --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值