--- title: 3.5、Docker(5)-容器连接 date: 2018-7-9 10:02:52 tags: - linux - docker categories: - linux --- 容器在运行当中, 经常需要连接到其他容器, 比如web程序需要连接到数据库 docker容器使用`link`参数来实现容器之间的连接, 从而可以完成不同容器之间的交互工作 ### SpringBoot程序容器化 例如在这个程序当中需要连接mysql与redis #### 启动reids与mysql容器 拉取镜像 ```bash docker pull redis:4.0 docker pull mysql:5.7 ``` 启动容器 ```bash # 启动redis容器 docker run \ -d \ --name redis-server \ redis:4.0 \ --requirepass "xyz654321" # 启动mysql容器 docker run \ -d \ --name mysql-server \ --env MYSQL_ROOT_PASSWORD=123456 \ mysql:5.7 ``` 这里指定了容器的名字( 在之后的容器连接当中要用到 ) 并且设置redis和mysql的密码 查看容器的运行情况 ![mysql与redis容器](/images/linux/mysql与redis容器.jpg) 我们在启动mysql容器的时候没有映射到宿主机端口 如果要连接进行数据库导入操作 可以查看这个容器的IP ![mysql容器IP地址](/images/linux/mysql_ip.jpg) > 这里推荐一个mysql的命令行客户端工具[mycli](https://github.com/dbcli/mycli) 具备语法补全功能, 是python写的 ![mycli](/images/linux/mycli.gif) 在ubuntu下使用`apt install mycli`安装 在centos下使用`pip install mycli`安装 这里我们就要根据容器的虚拟IP进行连接了 ```bash mycli -h 172.17.0.3 ``` 之后创建数据库testdb 创建用户test_user, 设置密码为abc123456, 并进行授权 #### SpringBoot配置文件 application.yml ```yaml server: port: 9000 mysql-host: 127.0.0.1 redis-host: 127.0.0.1 spring: datasource: url: jdbc:mysql://${mysql-host}:3306/testdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: test_user password: abc123456 redis: host: ${redis-host} port: 6379 password: xyz654321 ``` 这里把mysql与redis的主机地址单独拿出来作为一个配置项, 为了容器启动时可以方便进行传参控制 #### 项目代码 需要引入redis连接以及mysql连接相关的jar包 pom.xml ```xml org.springframework.boot spring-boot-starter-data-redis ${spring-boot.version} redis.clients jedis 2.9.0 org.springframework.boot spring-boot-starter-data-jpa ${spring-boot.version} mysql mysql-connector-java ${mysql-connector.version} ``` 配置执行连接redis的bean ```java @Configuration public class RedisConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.password}") private String password; @Bean public JedisConnectionFactory redisConnectionFactory() { RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration(); redisConfiguration.setHostName(host); redisConfiguration.setPort(port); redisConfiguration.setPassword(RedisPassword.of(password)); JedisClientConfigurationBuilder clientConfig = JedisClientConfiguration.builder(); clientConfig.connectTimeout(Duration.ofSeconds(60));// 60s connection timeout return new JedisConnectionFactory(redisConfiguration, clientConfig.build()); } @Bean public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); // 使用JdkSerializationRedisSerializer来序列化和反序列化redis的value值 RedisSerializer serializer = new JdkSerializationRedisSerializer(); template.setValueSerializer(serializer); template.afterPropertiesSet(); return template; } } ``` #### 构建镜像 将项目打包的jar文件放在一个独立目录当中(这里打包的文件是 **demo-1.0.0.jar**) 创建Dockerfile文件 ```docker FROM java:openjdk-8-jre COPY . /app WORKDIR /app RUN /bin/bash ./init.sh EXPOSE 9000 ENTRYPOINT ["java","-jar","demo-1.0.0.jar", \ "--mysql-host=mysqlhost", \ "--redis-host=redishost"] ``` + `RUN`指定运行了一个在打包镜像时执行的初始化脚本 如果没有可执行的, 可以去掉 + `ENTRYPOINT`在容器运行时执行, 也可以使用CMD + 传递mysql-host与redis-host是springboot本身支持的特性, 命令行传参的优先级比配置文件更高, 将会在运行时生效 ```bash # 打包镜像 docker build -t demo:1.0.0 /root/demo ``` #### 启动容器 ```bash docker run -d \ --rm \ --link redis-server:redishost \ --link mysql-server:mysqlhost \ -p 9000:9000 \ demo:1.0.0 ``` link是用来指定与哪个容器进行连接 例如`redis-server`是容器的名称, 后面的`redishost`是给这个连接指定一个别名 #### 原理浅析 这里我创建的容器ID是6f1e5d0844c5 我们可以通过shell进入这个容器查看内容 ```bash docker exec -it 6f1e5d0844c5 bash # 此时会切换到 root@6f1e5d0844c5 的shell cat /etc/hosts ``` 内容如下 ``` 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 redishost 7bb1eb2c8edc redis-server 172.17.0.3 mysqlhost b71e6ce961f0 mysql-server 172.17.0.4 6f1e5d0844c5 ``` 显然, 运行容器时link参数的作用只是在hosts里面给另外几个容器的添加了别名 所以我们执行数据库连接时才可以使用 `jdbc:mysql://mysqlhost:3306/testdb`作为URL地址 那么同理 使用`mysql-server`或者直接用IP`172.17.0.3`都没问题 至此也就可以理解了, link参数并不是必须的 在一台宿主机上运行的所有容器, 之间构成了一个虚拟的局域网 他们之间都可以直接进行访问 > 当然知道应用容器的IP之后, 我们可以指定mysql数据库里面test_user的绑定IP是`172.17.0.4`而不是% 以便保证安全