Docker容器 - compose容器编排(Java微服务项目实例,解决 docker-compose up Mysql 的报错问题)
ERROR: for mysqlCannot start service mysql: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/
目录
Creating jardocker_mysql_1 ... error
是什么
Docker-Compose是Docker官方的开源项目。负责实现对Docker容器集群的快速编排。可以管理多个 Docker 容器组成一个应用。你需要定义一个 yml 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。
这玩意儿可是个项目哇!
能干什么
还记得咱们Java里面怎么新建对象吗,直接new一个出来。
//没有对象怎么办 new一个出来
在spring里面,咱们是通过xml来对多个对象进行统一的管理:在容器applicationContext.xml中对bean对象进行统一集中的管理。
<bean id="" class="">
而在Docker中,容器之间的启动可能会存在一定的先后顺序,加载条件等因素。所以咱们使用docker compose来对容器实例进行统一的管理,这里要使用到yml文件:docker-compose.yml这样可以做到对大量的容器实例进行统一的一键start,一键stop等大量操作。
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。Compose允许用户通过一个单独的docker-compose.yml模板文件(yml格式)来定义一组相关联的应用容器为一个项目(project)。可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
安装
一、官网
官网地址:Compose file version 3 reference | Docker Documentation
可以看到左侧有2和3两个版本,官方给的建议是用v3。官网的内容其实非常多,跟着官网学其实也不错。
二、下载
下载地址:Install Docker Compose | Docker Documentation
这里只是把地址列出来,也不需要去官网下载再安装,直接跟着下一步来即可
官网的更新速度可能较快,直接跟着以下的步骤来
三、安装步骤
直接依次执行
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
检查到版本号后代表安装成功
四、卸载
这里就不做截图演示了,卸载时直接执行以下命令即可:
sudo rm /usr/local/bin/docker-compose
Compose核心概念
一、一个文件
docker-compose.yml
二、两个要素
1.服务(service)
一个个容器实例,比如微服务、mysql、Nginx、redis等
2.工程(project)
由一组关联的容器组成的一个完整的业务单元,在 docker-compose.yml 文件中进行定义。
Compose的操作步骤
使用的三个步骤如下:
编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
使用 docker-compose.yml 定义一个完整的业务单元,安排好整体应用中的各个容器服务
最后,执行 docker-compose up 命令来启动并运行整个应用程序,完整一键部署
Compose常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose down # 停止并删除容器、网络、卷、镜像
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
docker-compose exec yml里面的服务id # 进入容器实例内部
docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose up -d # 启动所有docker-compose服务并后台运行
Compose编排Java微服务
之前博客里写得发布微服务到容器其实里面也就只输出了一个UUID。这回咱们把mysql那些东西都加上,然后再使用docker compose进行编排管控。类如下:
因为本篇文章的重点不在于Java、mysql、redis等方面,直接上代码:
一、sql
CREATE TABLE `t_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表'
二、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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<!--<version>2.3.10.RELEASE</version>-->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>docker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mapper.version>4.1.5</mapper.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<dependencies>
<!--guava Google 开源的 Guava 中自带的布隆过滤器-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.4</version>
</dependency>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--SpringBoot与Redis整合依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--springCache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--springCache连接池依赖包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
<!--Mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--SpringBoot集成druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!--mybatis和springboot整合-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<!-- 添加springboot对amqp的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<!--通用基础配置junit/devtools/test/log4j/lombok/hutool-->
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<!--persistence-->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
</dependency>
<!--通用Mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>${mapper.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
</project>
三、YML
server.port=6001
# ========================alibaba.druid=========================
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.150.30:3306/dbtest?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=你自己的密码
spring.datasource.druid.test-while-idle=false
# ========================redis=========================
spring.redis.database=0
spring.redis.host=192.168.150.30
spring.redis.port=6379
spring.redis.password=
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
# ========================mybatis=======================
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=docker.entities
# ========================swagger=====================
spring.swagger2.enabled=true
四、主启动类
package docker.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReferenceUtil;
import docker.entities.User;
import docker.entities.UserDTO;
import docker.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Random;
@Api(description = "用户User接口")
@RestController
@Slf4j
public class UserController
{
@Resource
private UserService userService;
@ApiOperation("数据库新增3条记录")
@RequestMapping(value = "/user/add",method = RequestMethod.POST)
public void addUser()
{
for (int i = 1; i <=3; i++) {
User user = new User();
user.setUsername("van"+i);
user.setPassword(IdUtil.simpleUUID().substring(0,6));
user.setSex((byte) new Random().nextInt(2));
userService.addUser(user);
}
}
@ApiOperation("查询1条记录")
@RequestMapping(value = "/user/find/{id}",method = RequestMethod.GET)
public User findUserById(@PathVariable Integer id)
{
return userService.findUserById(id);
}
}
五、config配置类
1.RedisConfig
package docker.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.io.Serializable;
@Configuration
@Slf4j
public class RedisConfig {
/**
* @param lettuceConnectionFactory
* @return redis序列化的工具配置类,下面这个请一定开启配置
* 127.0.0.1:6379> keys *
* 1) "ord:102" 序列化过
* 2) "\xac\xed\x00\x05t\x00\aord:102" 野生,没有序列化过
*/
@Bean
public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
//设置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
2.SwaggerConfig
package docker.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.text.SimpleDateFormat;
import java.util.Date;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${spring.swagger2.enabled}")
private Boolean enabled;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(enabled)
.select()
.apis(RequestHandlerSelectors.basePackage("docker")) //你自己的package
.paths(PathSelectors.any())
.build();
}
public ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Java" + "\t" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()))
.description("docker-compose")
.version("1.0")
.termsOfServiceUrl("https://www.baidu.com/")
.build();
}
}
六、entities类
1.User
package docker.entities;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(generator = "JDBC")
private Integer id;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 性别 0=女 1=男
*/
private Byte sex;
/**
* 删除标志,默认0不删除,1删除
*/
private Byte deleted;
/**
* 更新时间
*/
@Column(name = "update_time")
private Date updateTime;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
/**
* @return id
*/
public Integer getId() {
return id;
}
/**
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取用户名
*
* @return username - 用户名
*/
public String getUsername() {
return username;
}
/**
* 设置用户名
*
* @param username 用户名
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取密码
*
* @return password - 密码
*/
public String getPassword() {
return password;
}
/**
* 设置密码
*
* @param password 密码
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取性别 0=女 1=男
*
* @return sex - 性别 0=女 1=男
*/
public Byte getSex() {
return sex;
}
/**
* 设置性别 0=女 1=男
*
* @param sex 性别 0=女 1=男
*/
public void setSex(Byte sex) {
this.sex = sex;
}
/**
* 获取删除标志,默认0不删除,1删除
*
* @return deleted - 删除标志,默认0不删除,1删除
*/
public Byte getDeleted() {
return deleted;
}
/**
* 设置删除标志,默认0不删除,1删除
*
* @param deleted 删除标志,默认0不删除,1删除
*/
public void setDeleted(Byte deleted) {
this.deleted = deleted;
}
/**
* 获取更新时间
*
* @return update_time - 更新时间
*/
public Date getUpdateTime() {
return updateTime;
}
/**
* 设置更新时间
*
* @param updateTime 更新时间
*/
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
/**
* 获取创建时间
*
* @return create_time - 创建时间
*/
public Date getCreateTime() {
return createTime;
}
/**
* 设置创建时间
*
* @param createTime 创建时间
*/
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
2.UserDTO
package docker.entities;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
@ApiModel(value = "用户信息")
public class UserDTO implements Serializable {
@ApiModelProperty(value = "用户ID")
private Integer id;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "性别 0=女 1=男 ")
private Byte sex;
@ApiModelProperty(value = "删除标志,默认0不删除,1删除")
private Byte deleted;
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
* @return id
*/
public Integer getId() {
return id;
}
/**
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取用户名
*
* @return username - 用户名
*/
public String getUsername() {
return username;
}
/**
* 设置用户名
*
* @param username 用户名
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取密码
*
* @return password - 密码
*/
public String getPassword() {
return password;
}
/**
* 设置密码
*
* @param password 密码
*/
public void setPassword(String password) {
this.password = password;
}
/**
* 获取性别 0=女 1=男
*
* @return sex - 性别 0=女 1=男
*/
public Byte getSex() {
return sex;
}
/**
* 设置性别 0=女 1=男
*
* @param sex 性别 0=女 1=男
*/
public void setSex(Byte sex) {
this.sex = sex;
}
/**
* 获取删除标志,默认0不删除,1删除
*
* @return deleted - 删除标志,默认0不删除,1删除
*/
public Byte getDeleted() {
return deleted;
}
/**
* 设置删除标志,默认0不删除,1删除
*
* @param deleted 删除标志,默认0不删除,1删除
*/
public void setDeleted(Byte deleted) {
this.deleted = deleted;
}
/**
* 获取更新时间
*
* @return update_time - 更新时间
*/
public Date getUpdateTime() {
return updateTime;
}
/**
* 设置更新时间
*
* @param updateTime 更新时间
*/
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
/**
* 获取创建时间
*
* @return create_time - 创建时间
*/
public Date getCreateTime() {
return createTime;
}
/**
* 设置创建时间
*
* @param createTime 创建时间
*/
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", sex=" + sex +
'}';
}
}
七、mapper类
1.UserMapper
package docker.mapper;
import docker.entities.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User> {
}
2.UserMapper.xml
在此处创建UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="docker.mapper.UserMapper">
<resultMap id="BaseResultMap" type="docker.entities.User">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="INTEGER" property="id" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="sex" jdbcType="TINYINT" property="sex" />
<result column="deleted" jdbcType="TINYINT" property="deleted" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
</resultMap>
</mapper>
八、service类
package docker.service;
import docker.entities.User;
import docker.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class UserService {
public static final String CACHE_KEY_USER = "user:";
@Resource
private UserMapper userMapper;
@Resource
private RedisTemplate redisTemplate;
/**
* addUser
*
* @param user
*/
public void addUser(User user) {
//1 先插入mysql并成功
int i = userMapper.insertSelective(user);
if (i > 0) {
//2 需要再次查询一下mysql将数据捞回来并ok
user = userMapper.selectByPrimaryKey(user.getId());
//3 将捞出来的user存进redis,完成新增功能的数据一致性。
String key = CACHE_KEY_USER + user.getId();
redisTemplate.opsForValue().set(key, user);
}
}
/**
* findUserById
*
* @param id
* @return
*/
public User findUserById(Integer id) {
User user = null;
String key = CACHE_KEY_USER + id;
//1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql
user = (User) redisTemplate.opsForValue().get(key);
if (user == null) {
//2 redis里面无,继续查询mysql
user = userMapper.selectByPrimaryKey(id);
if (user == null) {
//3.1 redis+mysql 都无数据
//你具体细化,防止多次穿透,我们规定,记录下导致穿透的这个key回写redis
return user;
} else {
//3.2 mysql有,需要将数据写回redis,保证下一次的缓存命中率
redisTemplate.opsForValue().set(key, user);
}
}
return user;
}
}
九、controller类
package docker;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan("docker.mapper") //import tk.mybatis.spring.annotation.MapperScan;
public class DockerBootApplication
{
public static void main(String[] args)
{
SpringApplication.run(DockerBootApplication.class, args);
}
}
十、打成jar包并上传
直接双机,在打包完成后上传至Linux,记得单独开一个目录来进行存放。
十一、编写Dockerfile
在刚刚用来存放jar包的目录下新建Dockerfile文件,注意文件名大小写。
# 基础镜像使用java
FROM java:8
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为van_docker.jar
ADD docker-0.0.1-SNAPSHOT.jar van_docker.jar
# 运行jar包
RUN bash -c 'touch /van_docker.jar'
ENTRYPOINT ["java","-jar","/van_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001
十二、构建镜像
注意最后的空格和点
docker build -t van_docker:1.6 .
构建成功。
不使用Compose
有compose不用就有点类似于有idea不用,偏偏要用记事本写代码
一、mysql容器实例
docker run -p 3306:3306 --name mysql57 --privileged=true -v /jardata/mysql/conf:/etc/mysql/conf.d -v /jardata/mysql/logs:/logs -v /jardata/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=你的密码 -d mysql:5.7
老规矩,别忘了ps看一眼
然后咱们进入容器看看:
docker exec -it mysql57 bash
mysql -uroot -p
然后我们需要开始建库建表,把之前的东西给扔进去:
create database dbtest;
use dbtest;
接着将之前的那一大段sql复制进去:
CREATE TABLE `t_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表'
表结构创建成功
二、redis容器实例
docker run -p 6379:6379 --name redis608 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
ps看一眼:
进入容器:
docker exec -it redis608 bash
这时候的mysql和redis都还是空的,而且都已经创建成功
三、微服务
注意自己的实际ID
docker run -d -p 6001:6001 965861d1a066
到了这里才算是把这三个玩意儿都起起来,但是这只是三个而已。实际的生产环境里有很大的概率会是几十个,要是这样一个一个起真的有点折寿。
swagger测试
一、验证写操作
这里要注意自己的真实IP:
http://192.168.150.30:6001/swagger-ui.html#/user-controller
点击右侧的Try it now ,然后点击弹出来的Execute
这里是发送了一个post请求
然后咱们返回到mysql查询一下看看:
接着去redis看看:
这里的写操作已经验证成功。
二、验证读操作
点击get里面的Try it now
我们这里查找一下1号记录,然后点击Execute
往下看结果
全部查询成功,到这里读操作也完成了。
存在的问题
咱们这里没有使用compose也成功达到了目的,但是存在着以下问题:
先后顺序要求固定,先mysql+redis才能启动微服务
过多的run
容器间的启停或宕机,有可能导致IP地址对应容器实例变化,映射出错,这时候就只能写死IP,要么通过服务调用
使用Compose
本篇的重点到这里才刚刚开始
一、编写docker-compose.yml文件
在之前上传jar包的目录下创建yml文件
vim docker-compose.yml
将以下内容复制进去:
version: "3"
services:
#微服务
microService:
image: van_docker:2.0
#镜像
container_name: ms01
#容器名称
ports:
#端口映射
- "6001:6001"
volumes:
#容器数据卷
- /app/microService:/data
networks:
#网络模式
- van_net
depends_on:
#依赖关系
- redis
- mysql
redis:
#redis
image: redis:6.0.8
#镜像
ports:
#端口映射
- "6379:6379"
volumes:
#容器数据卷
- /app/redis/redis.conf:/etc/redis/redis.conf
- /app/redis/data:/data
networks:
#网络模式
- van_net
command: redis-server /etc/redis/redis.conf
mysql:
#mysql
image: mysql:5.7
#镜像
environment:
#环境
MYSQL_ROOT_PASSWORD: 'zxcvbn0131'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'dbtest'
MYSQL_USER: 'van'
MYSQL_PASSWORD: 'zxcvbn0131'
ports:
#端口映射
- "3306:3306"
volumes:
#容器数据卷
- /app/mysql/db:/var/lib/mysql
- /app/mysql/conf/my.cnf:/etc/my.cnf
- /app/mysql/init:/docker-entrypoint-initdb.d
networks:
#网络模式
- van_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
#网络模式
van_net:
二、修改微服务项目
1.修改yml
复制以下内容,并覆盖粘贴(这里只是把原先的IP地址改成了服务名):
server.port=6001
# ========================alibaba.druid相关配置=====================
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://mysql:3306/dbtest?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=自己的密码
spring.datasource.druid.test-while-idle=false
# ========================redis相关配置=====================
spring.redis.database=0
spring.redis.host=redis
spring.redis.port=6379
spring.redis.password=
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
# ========================mybatis相关配置===================
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=docker.entities
# ========================swagger=====================
spring.swagger2.enabled=true
接着就跟之前一样,打包jar包,然后上传,替换掉原先的jar包。
Dockerfile这里就不用进行修改了,然后重建一个镜像出来:
docker build -t van_docker:2.0 .
然后把之前的三个容器直接停掉:
docker rm -f 1e071bfa04a3 c4855d7f87fd 426eac422e84
把之前构建的的1.6版本也给删了:
docker rmi -f 965861d1a066
接着要开始使用之前提到的常用命令了(建议在yml文件的目录下执行):
运行一个看看有没有问题:
docker-compose config -q
只要没有其它的任何提示,就代表操作没有问题。接下来开始正式启动:
docker-compose up -d
效果如下( 这里如果报错请看文章结尾 ):
我们可以顺便去看一眼docker的网络:
可以看到它在我们刚刚创建的(写在了docker-compose.yml里面)van_net网络模式前面加上了前缀。ps看一眼:
进入mysql容器看一眼,然后开始建库建表:
docker exec -it 0fd561357e08 bash
create database dbtest;
use dbtest;
sql:
CREATE TABLE `t_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ',
`deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表'
重建一次该表,再进去redis看一眼:
docker exec -it 04a23c342f44 bash
redis-cli
keys *
可以看到现在咱们的mysql和redis都是空的,开始重新进行测试。
三、再次进行swagger测试
这里需要注意自己的真实IP,再次访问进行测试:
http://192.168.150.30:6001/swagger-ui.html#/user-controller
写入数据
成功拿到数据,数据写入成功。
成功读取。
四、关停
docker-compose stop
五、报错
Creating jardocker_mysql_1 ... error
ERROR: for mysql Cannot start service mysql: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/app/mysql/conf/my.cnf" to rootfs at "/etc/my.cnf": mount /app/mysql/conf/my.cnf:/etc/my.cnf (via /proc/self/fd/6), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
ERROR: Encountered errors while bringing up the project.
docker-compose up 的过程中出现了以下报错:
这里的原因是因为创建的 my.cnf 的时候应该是个文件,而这里却是目录,去改一下即可,前往以下目录:
把它删了,然后创建一个同名的文件,然后再次启动 docker-compose up :
启动成功问题解决。
案例演示结束。
更多推荐
所有评论(0)