Docker 全栈体系(七)
Docker 体系(高级篇)
五、Docker-compose容器编排
1. 是什么
- Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
- Docker-Compose是Docker官方的开源项目, 负责实现对Docker容器集群的快速编排。
2. 能干嘛
- docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
- 如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具。
- 例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。。。。。。
- Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
- 可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
3. 去哪下
3.1官网
- https://docs.docker.com/compose/compose-file/compose-file-v3/
3.2 官网下载
- https://docs.docker.com/compose/install/
3.3 安装步骤
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
3.4 卸载步骤
4. Compose核心概念
4.1 一文件
- docker-compose.yml
4.2 两要素
- 服务(service)
- 一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
- 工程(project)
- 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
5. Compose使用的三个步骤
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
- 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
- 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
6. Compose常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
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 logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
7. Compose编排微服务
7.1 改造升级微服务工程docker_boot
7.1.1 以前的基础版
7.1.2 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='用户表'
7.1.3 改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.alex.docker</groupId><artifactId>docker_boot</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>
7.1.4 写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.111.169:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.druid.test-while-idle=false
# ========================redis相关配置=====================
spring.redis.database=0
spring.redis.host=192.168.111.169
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=com.atguigu.docker.entities
# ========================swagger=====================
spring.swagger2.enabled=true
7.1.5 主启动
package com.alex.docker;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;@SpringBootApplication
@MapperScan("com.alex.docker.mapper") //import tk.mybatis.spring.annotation.MapperScan;
public class DockerBootApplication
{public static void main(String[] args){SpringApplication.run(DockerBootApplication.class, args);}}
7.1.6 业务类
- config配置类
// RedisConfig
package com.alex.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" 野生,没有序列化过*/@Beanpublic RedisTemplate<String,Serializable> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){RedisTemplate<String,Serializable> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式jsonredisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}}
// SwaggerConfig
package com.alex.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;@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).enable(enabled).select().apis(RequestHandlerSelectors.basePackage("com.atguigu.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.alex.com/").build();}
}
- 新建entity
// User
package com.alex.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;}
}
// UserDTO
package com.alex.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;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", sex=" + sex +'}';}
}
- 新建mapper
// 新建接口UserMapperpackage com.alex.docker.mapper;import com.atguigu.docker.entities.User;
import tk.mybatis.mapper.common.Mapper;public interface UserMapper extends Mapper<User> {
}
- src\main\resources路径下新建mapper文件夹并新增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="com.alex.docker.mapper.UserMapper"><resultMap id="BaseResultMap" type="com.alex.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 com.alex.docker.service;import com.alex.docker.entities.User;
import com.alex.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:";@Resourceprivate UserMapper userMapper;@Resourceprivate RedisTemplate redisTemplate;/*** addUser* @param user*/public void addUser(User user){//1 先插入mysql并成功int i = userMapper.insertSelective(user);if(i > 0){//2 需要再次查询一下mysql将数据捞回来并okuser = 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里面查询,如果有直接返回结果,如果没有再去查询mysqluser = (User) redisTemplate.opsForValue().get(key);if(user == null){//2 redis里面无,继续查询mysqluser = userMapper.selectByPrimaryKey(id);if(user == null){//3.1 redis+mysql 都无数据//你具体细化,防止多次穿透,我们规定,记录下导致穿透的这个key回写redisreturn user;}else{//3.2 mysql有,需要将数据写回redis,保证下一次的缓存命中率redisTemplate.opsForValue().set(key,user);}}return user;}
}
- 新建controller
package com.alex.docker.controller;import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReferenceUtil;
import com.alex.docker.entities.User;
import com.alex.docker.entities.UserDTO;
import com.alex.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;/*** @auther zzyy* @create 2021-05-01 15:02*/
@Api(description = "用户User接口")
@RestController
@Slf4j
public class UserController
{@Resourceprivate 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("zzyy"+i);user.setPassword(IdUtil.simpleUUID().substring(0,6));user.setSex((byte) new Random().nextInt(2));userService.addUser(user);}}@ApiOperation("删除1条记录")@RequestMapping(value = "/user/delete/{id}",method = RequestMethod.POST)public void deleteUser(@PathVariable Integer id){userService.deleteUser(id);}@ApiOperation("修改1条记录")@RequestMapping(value = "/user/update",method = RequestMethod.POST)public void updateUser(@RequestBody UserDTO userDTO){User user = new User();BeanUtils.copyProperties(userDTO,user);userService.updateUser(user);}@ApiOperation("查询1条记录")@RequestMapping(value = "/user/find/{id}",method = RequestMethod.GET)public User findUserById(@PathVariable Integer id){return userService.findUserById2(id);}
}
7.1.7 mvn package命令将微服务形成新的jar包 并上传到Linux服务器/mydocker目录下
7.1.8 编写Dockerfile
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER alex
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
# 运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001
7.1.9 构建镜像
docker build -t zzyy_docker:1.6 .
7.2 不用Compose
7.2.1 单独的mysql容器实例
- 新建mysql容器实例
docker run -p 3306:3306 --name mysql57 --privileged=true -v /zzyyuse/mysql/conf:/etc/mysql/conf.d -v /zzyyuse/mysql/logs:/logs -v /zzyyuse/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
- 进入mysql容器实例并新建库db666+新建表t_user
docker exec -it mysql57 /bin/bash
mysql -uroot -p
create database db666;
use db666;
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=utf8mb4 COMMENT='用户表';
7.2.2 单独的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
7.2.3 微服务工程
docker run -d -p 6001:6001 zzyy_docker:1.6
7.2.4 上面三个容器实例依次顺序启动成功
7.3 swagger测试
- http://localhost:你的微服务端口/swagger-ui.html#/
7.4 上面成功了,有哪些问题?
- 先后顺序要求固定,先mysql+redis才能微服务访问成功
- 多个run命令…
- 容器间的启停或宕机,有可能导致IP地址对应的容器实例变化,映射出错, 要么生产IP写死(可以但是不推荐),要么通过服务调用
7.5 使用Compose
7.5.1 编写docker-compose.yml文件
version: "3"services:microService:image: zzyy_docker:1.6container_name: ms01ports:- "6001:6001"volumes:- /app/microService:/datanetworks: - alex_net depends_on: - redis- mysqlredis:image: redis:6.0.8ports:- "6379:6379"volumes:- /app/redis/redis.conf:/etc/redis/redis.conf- /app/redis/data:/datanetworks: - alex_netcommand: redis-server /etc/redis/redis.confmysql:image: mysql:5.7environment:MYSQL_ROOT_PASSWORD: '123456'MYSQL_ALLOW_EMPTY_PASSWORD: 'no'MYSQL_DATABASE: 'db666'MYSQL_USER: 'zzyy'MYSQL_PASSWORD: 'zzyy123'ports:- "3306:3306"volumes:- /app/mysql/db:/var/lib/mysql- /app/mysql/conf/my.cnf:/etc/my.cnf- /app/mysql/init:/docker-entrypoint-initdb.dnetworks:- alex_netcommand: --default-authentication-plugin=mysql_native_password #解决外部无法访问networks: alex_net:
7.5.2 第二次修改微服务工程docker_boot
7.5.2.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://192.168.111.169:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.url=jdbc:mysql://mysql:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.druid.test-while-idle=false# ========================redis相关配置=====================
spring.redis.database=0
#spring.redis.host=192.168.111.169
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=com.atguigu.docker.entities# ========================swagger=====================
spring.swagger2.enabled=true
7.5.2.2 mvn package命令将微服务形成新的jar包 并上传到Linux服务器/mydocker目录下
7.5.2.3 编写Dockerfile
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zzyy
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
# 运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001
7.5.2.4 构建镜像
docker build -t zzyy_docker:1.6 .
7.5.3 执行 docker-compose up 或者 执行 docker-compose up -d
7.5.4 进入mysql容器实例并新建库db666+新建表t_user
docker exec -it 容器实例id /bin/bash
mysql -uroot -p
create database db666;
use db666;
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=utf8mb4 COMMENT='用户表';
7.5.5 测试通过
7.5.6 关停
相关文章:

Docker 全栈体系(七)
Docker 体系(高级篇) 五、Docker-compose容器编排 1. 是什么 Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调…...

【编程范式】聊聊什么是数据类型和范式的本质
什么是编程范式 范式其实就是做事的方式,编程范式可以理解为如何编程,按照什么样的模式或者风格进行编程。 编程范式包含哪些 泛型编程函数式编程面向对象编程编程本质和逻辑编程 虽然有不同的编程范式,但是对于目的来说都是为了解决同一…...

2023-08-01 python根据x轴、y轴坐标(数组)在坐标轴里画出曲线图,python 会调用鼎鼎大名的matlib,用来分析dac 数据
一、python 源码如下 import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt#x[0 ,1,2,3,5,6,10] #y[0,0,3,4,5,7,8]# { 0 , 1 , 0x0003 },// 0 # { 0XFFFF * 1 / 10 , 3006 , 0x0a6b },// 1 # { 0XFFFF * 2 / 10 , 599…...

小研究 - 主动式微服务细粒度弹性缩放算法研究(四)
微服务架构已成为云数据中心的基本服务架构。但目前关于微服务系统弹性缩放的研究大多是基于服务或实例级别的水平缩放,忽略了能够充分利用单台服务器资源的细粒度垂直缩放,从而导致资源浪费。为此,本文设计了主动式微服务细粒度弹性缩放算法…...

机器学习深度学习——softmax回归的简洁实现
👨🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习&&深度学习——softmax回归从零开始实现 📚订阅专栏:机器学习&&深度学习 希望文章对你…...

CPU利用率过高解决思路
文章目录 问题场景问题定位问题解决 本文参考: Linux服务器之CPU过高解决思路_linux cpu温度过高_Jeremy_Lee123的博客-CSDN博客 Java程序员必备:jstack命令解析 - 掘金 (juejin.cn) 重点问题!CPU利用率过高排查思路|原创 (qq.…...

Redis(三)—— Redis基本的事务操作、Redis实现乐观锁
一、Redis基本的事务操作 首先声明: redis的单条命令是保证原子性的(回想一下setnx k1 v1 k5 v5命令如果k1已经存在,那么k5也会设置失败)但是redis的事务不保证原子性!见下面“1.2 某条命令有错怎么办?”…...

SQLI_LABS攻击
目录 Less1 首先来爆字段 联合注入 判断注入点 爆数据库名 爆破表名 information_schema information_schmea.tables group_concat() 爆破列名 information_schema.columns 爆值 SQLMAP Less-2 -4 Less -5 布尔 数据库 表名 字段名 爆破值 SQLMAP Less-6 …...

如何查看 Chrome 网站有没有前端 JavaScript 报错?
您可以按照以下步骤在Chrome中查看网站是否存在前端JavaScript报错: 步骤1:打开Chrome浏览器并访问网站 首先,打开Chrome浏览器并访问您想要检查JavaScript报错的网站。 步骤2:打开开发者工具 在Chrome浏览器中,按…...

JS前端读取本地上传的File文件对象内容(包括Base64、text、JSON、Blob、ArrayBuffer等类型文件)
读取base64图片File file2Base64Image(file, cb) {const reader new FileReader();reader.readAsDataURL(file);reader.onload function (e) {cb && cb(e.target.result);//即为base64结果}; }, 读取text、JSON文件File readText(file, { onloadend } {}) {const re…...

【项目方案】OpenAI流式请求实现方案
文章目录 实现目的效果比对非stream模式stream模式实现方案方案思路总体描述前端方案对比event-source-polyfill代码示例前端实现遇到的问题与解决方法后端参考资料时序图关键代码示例后端实现时遇到的问题与解决方法实现目的 stream是OpenAI API中的一个参数,用于控制请求的…...

华为数通HCIP-IP组播基础
点到点业务:比如FTP,WEB业务,此类业务主要特点是不同的用户有不同的需求,比如用户A需要下载资料A,用户B需要下载资料B。此类业务一般由单播承载,服务器对于不同用户发送不同的点到点数据流。 ospf、isis…...

STM32 SPI学习
SPI 串行外设设备接口(Serial Peripheral Interface),是一种高速的,全双工,同步的通信总线。 SCK时钟信号由主机发出。 SPI接口主要应用在存储芯片。 SPI相关引脚:MOSI(输出数据线ÿ…...

分布式缓存与数据库的一致性记录
用户更新数据库,需要再去更新redis缓存,否则会造成缓存与数据库数据不一致 一致性的两种方法 1). 双写模式 更新完数据库之后,更新redis缓存数据 问题: 因为请求时间的问题,造成缓存数据不是最新的 数据。 原因:A先修…...

vue3的语法
main.js中写发生变化,并不兼容vue2的写法 //vue3 import { createApp } from vue import ./style.css import App from ./App.vuecreateApp(App).mount(#app)//vue2 import Vue from vue import ./style.css import App from ./App.vueconst vm new Vue({render:h…...

【git合并分支自定义提交消息】
开发分支 dev主分支 master 需求 dev分支开发完后合并到master分支自定义提交信息 通过 git merge dev --squash --no-commit此命令会拉取dev分支代码到当前分支,并不会自动提交,可以自己修改提交信息...

AttributeError: module ‘PyQt5.QtGui‘ has no attribute ‘QMainWindow‘
场景描述: 这个问题是使用PyUIC将ui文件变成py文件后遇到的 解决办法: 改动1:把object改成QtWidgets.QMainWindow 改动2:增加__init__函数,函数结构如下: def __init__(self):super(Ui_MainWindow,self).…...

基于Java+SpringBoot+Vue前后端分离电商项目
晚间lucky为友友们送福利啦~🎁 Tips:有需要毕业设计指导的童鞋一定要认真看哦,文末有彩蛋。 一.项目介绍 该电商项目是一个简单、入门级的电商项目,是基于JavaSpringBootVue前后端分离项目。前端采用两套独立的系统分别完成项目…...

Rpc服务消费者(Rpc服务调用者)实现思路
Rpc服务消费者(Rpc服务调用者)实现思路 前面几节说到Rpc消费者主要通过UserServiceRPc_Stub这个protobuf帮我们生成的类来实现,上代码回顾一下 class UserServiceRpc_Stub : public UserServiceRpc {public:UserServiceRpc_Stub(::PROTOBUF…...

FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法
FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法 一般情况下,为了方便用户控制工装夹具上的电磁阀等控制工具,FANUC机器人出厂时给我们提供了8个RO输出信号,如下图所示,这8个RO信号可以各自单独使用。 那么,如果为了安全控制,需要将2个RO信号成对的进行安全互锁…...

权威认可|云畅科技再次入选中国信通院「高质量数字化转型产品及服务全景图」
7月27日,由中国信通院主办的2023数字生态发展大会暨中国信通院“铸基计划”年中会议在北京成功召开。 会上,中国信通院重磅发布了「高质量数字化转型产品及服务全景图(2023)」,云畅科技凭借其自研产品「万应低代码」在…...

爬虫小白-如何调试列表页链接与详情链接不一样并三种方式js逆向解决AES-ECB
目录 一、网站分析二、定位监听三、熟悉AES-ECB四、调试分析五、node运行js六、Python执行js 一、网站分析 三年前的案例,我的原始文章网站 ,如图我们直接点击标题进入到详情页,链接会发生跳转,且与我们在详情看到的链接…...

Ubuntu 离线部署的常见操作
Ubuntu 离线安装的常见操作 **说明:**很多情况下,生产环境都是离线环境,然而开发环境都是互联网的环境,因此部署的过程中需要构建离线安装包; 1. 下载但是不安装 # 例如使用 apt 下载 wireshark 安装包 sudo apt download wireshark # 下载…...

什么是多运行时架构?
服务化演进中的问题 自从数年前微服务的概念被提出,到现在基本成了技术架构的标配。微服务的场景下衍生出了对分布式能力的大量需求:各服务之间需要相互协作和通信,以及共享状态等等,因此就有了各种中间件来为业务服务提供这种分…...

【MySQL】mysql | linux | 离线安装mysqldump
一、说明 1、项目要求离线安装mysqldump 2、数据库服务已经使用docker进行安装,但是其他项目依赖mysqldump,所以需要在宿主机上安装mysqldum 二、解决方案 1、下载依赖 https://downloads.mysql.com/archives/community/ 2、下载内容 mysql-community-c…...

中国农村程序员学习此【JavaScript教程】购买大平层,开上帕拉梅拉,迎娶白富美出任CEO走上人生巅峰
注:最后有面试挑战,看看自己掌握了吗 文章目录 在 Switch 语句添加多个相同选项从函数返回布尔值--聪明方法undefined创建 JavaScript 对象通过点号表示法访问对象属性使用方括号表示法访问对象属性通过变量访问对象属性给 JavaScript 对象添加新属性删除…...

【Python】Web学习笔记_flask(2)——getpost
flask提供的request请求对象可以实现获取url或表单中的字段值 GET请求 从URL中获取name、age两个参数 from flask import Flask,url_for,redirect,requestappFlask(__name__)app.route(/) def index():namerequest.args.get(name)agerequest.args.get(age)messagef姓名:{nam…...

RabbitMQ 教程 | 第5章 RabbitMQ 管理
👨🏻💻 热爱摄影的程序员 👨🏻🎨 喜欢编码的设计师 🧕🏻 擅长设计的剪辑师 🧑🏻🏫 一位高冷无情的编码爱好者 大家好,我是 DevO…...

LLM微调 | Adapter: Parameter-Efficient Transfer Learning for NLP
目的:大模型预训练+微调范式,微调成本高。adapter只只微调新增的小部分参数【但adapter增加了模型层数,引入了额外的推理延迟。】 Adapters最初来源于CV领域的《Learning multiple visual domains with residual adapters》一文,其核心思想是在神经网络模块基础上添加一些残…...

在idea中添加try/catch的快捷键
在idea中添加try/catch的快捷键 在idea中添加try/catch的快捷键 ctrlaltt 选中想被try/catch包围的语句,同时按下ctrlaltt, 出现下图 选择try/catch即可。...