容器化时代,看山不是山,看天全是云~
文章核心内容,可快速完成SpringBoot服务+依赖服务一起编排,完成服务容器化
docker-compose编排Redis,附有原生docker命令对比和docker编排指令的注释说明
docker-compose编排MySQL,注明核心配置
docker-compose编排SpringBoot微服务(这里以一个简单的SpringBoot集成Redis&MySQL服务代替)
SpringBoot调用Redis、MySQL容器提供的服务,编排时的依赖关系处理
文章注意前提事项说明
需要掌握Docker的基本使用,文章不会对基础命令进行过多说明
此处的服务使用SpringBoot,其他可以连接Redis和MySQL的服务也可以
容器间相互连通有两大方式
docker的基础和docker-compose前置知识可以参考本专栏的前面的文章
tip:通过容器名进行相互连通的容器间必须要加入到同一个网络
编写redis的docker-compose.yml配置文件,参数含义参考注释
不同的编排文件建议放到单独的文件夹中,比如单独新建一个redis目录,mysql的就创建mysql目录,依次类推
# 原始命令:
# docker run -d --name redis -p 6379:6379 -v \
# - /root/docker/compose/redis/redis.conf:/etc/redis/redis.conf \
# - /root/docker/compose/redis/data:/data \
# --network my_network redis:latest redis-server /etc/redis/redis.conf
# 版本号
version: "3"
# 服务列表,命令:docker run
services:
# 服务名称,任意,不重复即可
redis:
# 指定服务名称,命令:--name redis
# 如果不指定,则将默认用docker-compose.yml所在文件夹名_服务名称_n命名
container_name: redis
# 指定镜像:命令 redis:latest
image: redis:latest
# 指定端口:命令 -p 主机端口:容器端口
ports:
- "6379:6379"
# 数据容器卷
volumes:
- /root/docker/compose/redis/redis.conf:/etc/redis/redis.conf
- /root/docker/compose/redis/data:/data
# 加入指定网络,容器间必须要处于同一个网络才能通过容器名称进行调用
networks:
- my_network
# 运行命令
command: redis-server /etc/redis/redis.conf
# 创建网络
networks:
# 默认将会创建为 docker-compose.yml所在 文件夹名_my_network 网络名称
my_network:
复制代码
# docker-compose up
Creating network "compose_my_network" with the default driver
Creating redis ... done
Attaching to redis
redis | 1:C 24 Mar 2022 00:13:38.331 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis | 1:C 24 Mar 2022 00:13:38.331 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis | 1:C 24 Mar 2022 00:13:38.332 # Configuration loaded
redis | 1:M 24 Mar 2022 00:13:38.332 * monotonic clock: POSIX clock_gettime
复制代码
# docker-compose exec redis bash
root@f5865bc42306:/data# redis-cli
复制代码
# docker network ls
NETWORK ID NAME DRIVER SCOPE
012d4d17c012 bridge bridge local
# 默认将会创建为 docker-compose.yml所在文件夹名_my_network 网络名称
88c54133c87a compose_my_network bridge local
1524da0505ee host host local
f4cbc4779eaf none null local
复制代码
[
{
"Name": "compose_my_network",
"Id": "88c54133c87a04cc8c86a55c240d2ccafb9bfb456b8e7d185a9a246b5d274025",
"Created": "2022-03-24T00:13:37.623603357Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"f5865bc42306380b1bd72690d6f67d8abdd46a240a96ea5f9bcfee412fe76c17": {
"Name": "redis",
"EndpointID": "8638b4c9850e533778d331bfd916b120f8a1ac59a9f547763c5e352df93ed897",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
# 内部实际名称还是my_network
"com.docker.compose.network": "my_network",
# 容器编排项目名称
"com.docker.compose.project": "compose",
"com.docker.compose.version": "1.29.2"
}
}
]
复制代码
# docker-compose down
Removing redis ... done
Removing network compose_my_network
复制代码
注意这里只贴出了compose的构建配置,等同的docker命令参考redis部分,只是内容变了,但是等级等价的命令并没有太大差异
version: "3"
services:
mysql:
container_name: mysql
image: mysql:5.7
ports:
- "33306:3306"
environment:
# 等同于 -e MYSQL_ROOT_PASSWORD指定root的登录密码
MYSQL_ROOT_PASSWORD: 'tianxin'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
# 这里这个指令compose启动成功后会自动创建名为docker的数据库
MYSQL_DATABASE: 'docker'
# 此处就是相当于 mysql create user,创建了数据库的登录用户
MYSQL_USER: 'docker'
MYSQL_PASSWORD: '123456'
volumes:
- /root/docker/compose/mysql/data:/var/lib/mysql
# 这里的my.cnf可以从原来的安装的MySQL里面找,如果没有不配置也不影响,只是为了方便外部更改
- /root/docker/compose/mysql/conf/my.cnf:/etc/my.cnf
- /root/docker/compose/mysql/init:/docker-entrypoint-initdb.d
networks:
# 注意加入同一个网络
- my_network
# 解决外部无法访问
command: --default-authentication-plugin=mysql_native_password
networks:
my_network:
复制代码
# docker-compose exec mysql bash
root@6cb40ff45da5:/# mysql -uroot -ptianxin
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
# 这里可以看到,自动创建了docker数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| docker |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> use docker;
Database changed
mysql> show tables;
Empty set (0.00 sec)
复制代码
tip:MySQL和Redis相对于独立,但是对于服务而言,依赖于Redis和MySQL,所以在服务启动前需要先启动Redis和MySQL,如果依赖服务较多,人工管理是一件比较麻烦的事情。通过docker-compose的编排可以指定依赖关系等等
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.4.3
com.codecoord
docker
1.0
1.8
UTF-8
1.8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
com.baomidou
mybatis-plus-boot-starter
3.5.1
mysql
mysql-connector-java
com.alibaba
druid-spring-boot-starter
1.2.5
org.projectlombok
lombok
org.springframework.boot
spring-boot-maven-plugin
复制代码
特别说明:服务依赖的容器服务,使用容器服务名称,比如 jdbc:mysql://mysql:3306/docker,不要通过IP。端口号是容器内部端口,不是外部端口号!比如 -p 13306:3306,13306是对外端口,3306才是容器内部服务端口,服务依赖时不要指定为外部端口,生产中也不建议除了服务外的容器直接对外提供访问
server:
port: 80
spring:
redis:
port: 6379
# redis:依赖的服务
host: redis
datasource:
# mysql:依赖的服务,注意端口是容器端口,非宿主机端口
url: jdbc:mysql://mysql:3306/docker?userSSL=false
username: root
password: tianxin
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
复制代码
import com.codecoord.docker.domain.User;
import com.codecoord.docker.service.UserService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
@RestController
@RequestMapping("/docker")
public class DockerController {
@Resource
private UserService userService;
@Resource
private RedisTemplate redisTemplate;
@RequestMapping("/list")
public List list() {
return userService.list();
}
@RequestMapping("/add")
public boolean add() {
return userService.save(new User() {{
setName(UUID.randomUUID().toString());
}});
}
@RequestMapping("/get/{id}")
public Object get(@PathVariable("id") Long id) {
Map returnMap = new HashMap<>();
Object cache = redisTemplate.opsForValue().get(id);
if (Objects.nonNull(cache)) {
returnMap.put("data", cache);
returnMap.put("cache", "缓存命中");
return returnMap;
}
User user = userService.getById(id);
returnMap.put("data", user);
returnMap.put("cache", "缓存未命中");
redisTemplate.opsForValue().set(id.toString(), user);
return returnMap;
}
}
复制代码
先安装java:8镜像,参考Docker-高级篇(1)-Dockerfile(核心&构建Redis&构建JDK8) - 掘金 (juejin.cn)
# 基础镜像使用java8,需要先构建
FROM java:8
# 作者
MAINTAINER [email protected]
# 容器卷,指定临时文件的目录为/tmp
VOLUME /tmp
# 指定工作目录
WORKDIR /tmp
# 重命名可选操作,方便docker ps查看
add docker-1.0.jar core_service.jar
# 运行jar包
ENTRYPOINT ["java", "-jar", "core_service.jar"]
# 暴露30001端口作为服务端口
EXPOSE 30001
复制代码
# 构建镜像
# docker build -t core_service:1.0 .
Sending build context to Docker daemon 245.5MB
Step 1/7 : FROM java:8
---> 95064f52c03b
Step 2/7 : MAINTAINER [email protected]
---> Running in 4e2fe1672499
Removing intermediate container 4e2fe1672499
---> e17943871098
Step 3/7 : VOLUME /tmp
---> Running in b7f7d56bc0cf
Removing intermediate container b7f7d56bc0cf
---> 7b67adbb7378
Step 4/7 : WORKDIR /tmp
---> Running in 973e07d965cb
Removing intermediate container 973e07d965cb
---> 70f5211073eb
Step 5/7 : add docker-1.0.jar core_service.jar
---> 5015d0feafeb
Step 6/7 : ENTRYPOINT ["java", "-jar", "core_service.jar"]
---> Running in a8b45a171493
Removing intermediate container a8b45a171493
---> 0e9ea7fb43c7
Step 7/7 : EXPOSE 30001
---> Running in 01e5efc042a6
Removing intermediate container 01e5efc042a6
---> af170edd9100
Successfully built af170edd9100
Successfully tagged core_service:1.0
复制代码
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
core_service 1.0 af170edd9100 58 seconds ago 648MB
java 8 95064f52c03b 8 minutes ago 610MB
centos 7 eeb6ee3f44bd 6 months ago 204MB
复制代码
version: "3"
services:
macro_server:
image: core_service:1.0
container_name: core_service
ports:
- "80:80"
volumes:
- /root/docker/compose/app:/data
# 指定网络,这一步必须要和以来的服务处于统一网络
networks:
- my_network
# 依赖于redis和mysql,在启动本服务之前会先启动依赖的服务
depends_on:
- redis
- mysql
# Redis服务
redis:
container_name: redis
image: redis:latest
ports:
- "6379:6379"
volumes:
- /root/docker/compose/redis/redis.conf:/etc/redis/redis.conf
- /root/docker/compose/redis/data:/data
networks:
- my_network
command: redis-server /etc/redis/redis.conf
# MySQL服务,上面的构建服务直接拷贝下来即可
mysql:
container_name: mysql
image: mysql:5.7
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: 'tianxin'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'docker'
MYSQL_USER: 'docker'
MYSQL_PASSWORD: '123456'
volumes:
- /root/docker/compose/mysql/data:/var/lib/mysql
- /root/docker/compose/mysql/conf/my.cnf:/etc/my.cnf
- /root/docker/compose/mysql/init:/docker-entrypoint-initdb.d
networks:
- my_network
command: --default-authentication-plugin=mysql_native_password
networks:
my_network:
复制代码
# docker-compose up
Creating network "compose_my_network" with the default driver
Creating redis ... done
Creating mysql ... done
Creating core_service ... done
...
复制代码
docker exec -it mysql bash
复制代码
use docker;
create table user
(
id int primary key auto_increment,
name varchar(50),
create_time datetime not null default current_timestamp,
modify_time datetime not null default current_timestamp on update current_timestamp
);
复制代码