docker compose 基本使用

概述

docker compose 是一个工具,轻松和高效管理多个容器;批量容器编排;方便一次性管理多个容器

compose 是docker官方的开源项目,需要单独安装;

docker compose 可以集中的管理整个服务的运行环境和依赖关系,方便的上线和下线操作。

您可以使用 YAML 文件来配置应用程序的服务。然后,使用一个命令,您可以从您的配置中创建并启动所有服务。

官方地址: https://docs.docker.com/compose/

使用docker compose 三个步骤

  1. 定义应用的可以运行的dockerfile
  2. 通过 docker-compose.yml 定义服务运行的环境,使其能够在隔离的容器中运行
  3. 使用 docker compose up 快速运行环境

docker compose 整个生命周期

  • 启动,停止和构建服务
  • 查看服务的状态
  • 流动输出服务的运行日志
  • 在服务上运行一次性命令

安装docker compose

安装步骤: https://docs.docker.com/compose/install/

​ 以linux为例说明

  1. 首先需要安装docker 服务

  2. github 下载二进制文件

    1
    curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
  3. 赋予文件执行权限

    1
    chmod +x /usr/local/bin/docker-compose
  4. 验证

    1
    docker-compose version
    1
    2
    3
    4
    5
    docker-compose version 1.29.2, build 5becea4c
    docker-py version: 5.0.0
    CPython version: 3.7.10
    OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019

    基本概念

    服务

    对应compose 中定义的一个一个的容器实例,就称为是一个服务。比如mysql容器 比如web服务容器。

    工程

    由一组容器组成的一个整体,可以认为一个docker-compose.yml 组成的整个服务为一个工程。

docker compose 常用命令

需要在docker-compose.yml 相同目录下执行

  • docker-compose -h 帮助
  • docker-compose up [-d] 启动所有服务
  • docker-compose down 停止并删除容器和网络
  • docker-compose restart 重启
  • docker-compose start 启动
  • docker-compose stop 停止
  • docker-compose config [-q有问题才输出] 检查配置
  • docker-compose logs 日志信息
  • docker-compose exec 进人容器内部

docker compose 文件编写简单说明

  1. 文件格式可以使用yml 或yaml 文件名称必须为 docker-compose.yml, docker-compose.yaml, compose.yml, compose.yaml 中的一个文件名

  2. 文件需要执行版本,目前基本上都是用3.x 版本,不同的版本选择和docker版本有对应关系

详细配置文档 https://docs.docker.com/compose/compose-file/compose-file-v3/

常用配置说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
version: "xx" 首先需要定义版本号,固定写法,表示当前的文件的版本号说明
services: 配置多个服务
webapp: 名字未 webapp的服务
build: 配置通过dockerFile进行构建
context: ./dir 对应的路径,比如dockerfile的路径
dockerfile: Dockerfile-alternate dockerfile的名称
container_name: 自定义容器名称,如果不定义 默认为目录名称 + service 名称

image: mysql 基于那个镜像构建
volumes: 容器卷配置
- db-data:/var/lib/mysql/data
networks: 网络配置
- overlay

depends_on: //依赖那些服务,这些服务先起来后,本服务再启动,用来定义服务的启动顺序
- db
- redis

environment: //添加容器的环境变量设置
xx:xx
expose: //对外暴露端口
-"3001"

labels: 添加docker镜像的label

network_mode:

networks: 定义网络相关配置


spring boot 使用docker compose 部署服务

使用一个测试的springboot 项目,外部服务依赖 mysql和redis

数据访问使用spring-data-jpa redisTemplate

基本依赖配置

demo springboot项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

实体类和配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
=====entity

@Data
@Entity
@Table(name = "t_user",
uniqueConstraints=
@UniqueConstraint(columnNames={"id"}))
public class User implements Serializable {

@Id
@GeneratedValue
private Long id;

private String userName;

private int sex;


}

=======dao


@Repository
public interface UserRepositoryImpl extends CrudRepository<User,Long> {
}

=======boot


@EnableJpaRepositories
@SpringBootApplication
public class ComposeDemoApplication {

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


@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}


=====yml


server:
port: 8080

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
username: root
password: 123456

redis:
host: 127.0.0.1
database: 0

jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
show-sql: true
hibernate:
ddl-auto: update

定义了4个web接口,用来访问数据库和redis测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

@RequestMapping("/user")
@RestController
public class UserController {

@Resource
private UserRepositoryImpl userRepositoryImpl;

private static AtomicInteger count = new AtomicInteger(0);

@Resource
private RedisTemplate<String,User> redisTemplate;

private static final String USER_KEY = "cache_user";


@RequestMapping("/insert")
public Boolean insert(){
User user = new User();
user.setUserName("张三"+count.incrementAndGet());
user.setSex(count.get() % 2);
userRepositoryImpl.save(user);
return Boolean.TRUE;
}


@RequestMapping("/getAll")
public List<User> getAll(){
Iterable<User> allUser = userRepositoryImpl.findAll();
Iterator<User> iterator = allUser.iterator();
List<User> users = new ArrayList<>();
while (iterator.hasNext()){
users.add(iterator.next());
}
return users;
}



@RequestMapping("/toCache/{id}")
public Boolean toCache(@PathVariable(value = "id") Long id){
Optional<User> userOptional = userRepositoryImpl.findById(id);
if(userOptional.isPresent()){
ValueOperations<String, User> stringObjectValueOperations = redisTemplate.opsForValue();
stringObjectValueOperations.set(USER_KEY+":"+id,userOptional.get());
return Boolean.TRUE;
}
return Boolean.FALSE;
}


@RequestMapping("/getFromCache/{id}")
public User getFromCache(@PathVariable(value = "id") Long id){
ValueOperations<String, User> stringObjectValueOperations = redisTemplate.opsForValue();
Object obj = stringObjectValueOperations.get(USER_KEY + ":" + id);
if(obj != null){
return (User)obj;
}
return null;
}


}

http://localhost:8080/user/insert 插入一个新数据

http://localhost:8080/user/getAll 获取所有数据

http://localhost:8080/user/toCache/1 id 为1 放入redis

http://localhost:8080/user/getFromCache/1 获取id 为1 从redis中获取

  1. 修改配置中的服务请求地址,这里的请求的host 名称 需要是 dockercompose的服务名称一致。和微服务中根据服务名称调用的做法类似。

修改文件,在docker-compose中统一部署服务,对应的服务的地址不写死,而使用对应的服务名进行访问,所以

配置文件修改为

  1. 打包和上传

    使用maven 打包数据jar包放到服务器上

1
mvn package -DskipTests=true

获取springboot jar包传到服务器的指定目录

  1. 编写服务的dockerFile文件

    1
    vim serverDockerFile 
    1
    2
    3
    4
    5
    6
    FROM openjdk:8
    RUN mkdir -p /usr/src/app
    COPY ./compose-0.0.1-SNAPSHOT.jar /usr/src/app/app.jar
    WORKDIR /usr/src/app
    EXPOSE 8080
    ENTRYPOINT ["java","-jar","app.jar"]
  2. 创建redis 和mysql的外部配置 和数据目录 。

    对于容器内的数据和配置,不要放到容器内,通过数据卷的方式映射外部路径

1
2
3
4
[root@localhost boot-server]# mkdir -p  redis/conf
[root@localhost boot-server]# mkdir -p redis/data
[root@localhost boot-server]# mkdir -p mysql/data
[root@localhost boot-server]# mkdir -p mysql/conf
  1. 编写docker-compose.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    version: '3.6'
    services:
    web_server:
    build:
    context: .
    dockerfile: serverDockerFile
    ports:
    - "8080:8080"
    depends_on:
    - mysql
    - redis
    networks:
    - my_server_network
    container_name: webServer
    redis:
    image: redis:5.0.14
    volumes:
    - /usr/local/boot-server/redis/conf:/usr/local/etc/redis
    - /usr/local/boot-server/redis/data:/data
    ports:
    - "6379:6379"
    networks:
    - my_server_network
    container_name: redis

    mysql:
    image: mysql:5.7
    volumes:
    - /usr/local/boot-server/mysql/conf:/etc/mysql
    - /usr/local/boot-server/mysql/data:/var/lib/mysql
    environment:
    - MYSQL_ROOT_PASSWORD=123456
    privileged: true
    ports:
    - "3306:3306"
    networks:
    - my_server_network
    container_name: mysql
    networks:
    my_server_network:
    name: server_network


  2. 启动服务

    docker-compose up

  3. 测试服务,通过调用接口的方式测试服务的正常访问

当需要停止服务的时候

docker-compose stop 全部停止

docker-compose start 全部开启

docker-compose logs 查看日志输出