10.Docker Compose容器编排

文章目录

  • Compose简介
  • 安装和卸载步骤
  • 核心概念
    • compose文件
    • 两要素
  • 使用步骤
  • Compose常用命令
  • 微服务测试
    • 本地编码
    • 打包
    • 编写Dockerfile文件
    • 构建镜像
  • 不使用Compose调试
  • 使用Compose调试
  • WordPress测试验证增量更新

Compose简介

​ docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来。但是这样我们又面临以下问题:

​ 如果我需要同时部署好多个服务,那么每个服务需要单独编写Dockerfile文件、构建镜像、构建容器等步骤,非常麻烦。所以docker官方给我们提供了docker-compose多服务部署的工具。

例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器、redis服务器、注册中心eureka、负载均衡容器等。

Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose解决了容器与容器之间如何管理编排的问题。

总结:Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排,可以管理多个Docker容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令就能同时启动/关闭这些容器。

官方网站:https://docs.docker.com/compose/

安装和卸载步骤

一般情况下,安装docker engine时会自带docker compose。docker engine的详细安装可看博客:2.核心概念与安装配置

手动安装compose:https://docs.docker.com/compose/install/

核心概念

compose文件

​ Compose文件的默认路径是在当前工作目录中的compose.yaml(推荐)或compose.yml文件。为早期版本的向后兼容性Compose也支持docker-compose.yamldocker-compose.yml。如果这两个文件都存在,Compose更倾向于使用规范的compose.yaml

两要素

  • 服务(service)

    一个个应用容器实例,比如各种微服务、mysql容器、nginx容器、redis容器等

  • 工程(project)

    由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml文件中定义。

使用步骤

  1. 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
  2. 使用docker-compose.yml定义一个完整的业务单元,安排好整体应用中的各个容器服务
  3. 执行docker compose up命令启动运行整个应用程序,完成一件部署上线

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      # 停止服务

微服务测试

本地编码

  1. 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 http://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.zyn.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>
    
  2. application.yaml

    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.10.101:3306/boot_docker?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.10.101
    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.wang.docker.entities
    # ========================swagger=====================
    spring.swagger2.enabled=true
    
  3. 主启动类

    package com.wang.docker;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import tk.mybatis.spring.annotation.MapperScan;
    
    /**
     * @ClassName: DockerBootApplication
     * @Description
     * @Version 1.0
     */
    @SpringBootApplication
    @MapperScan("com.wang.docker.mapper") //import tk.mybatis.spring.annotation.MapperScan;
    public class DockerBootApplication {
        public static void main(String[] args) {
            SpringApplication.run(DockerBootApplication.class,args);
        }
    }
    

业务类如下:

  1. config配置类

    RedisConfig.java

    package com.wang.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;
    
    /**
     * @ClassName: RedisConfig
     * @Description
     * @Version 1.0
     */
    
    @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;
        }
    
    }
    

    SwaggerConfig.java

    package com.wang.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;
    
    /**
     * @ClassName: SwaggerConfig
     * @Description
     * @Version 1.0
     */
    @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("com.wang.docker")) //你自己的package
                    .paths(PathSelectors.any())
                    .build();
        }
    
        public ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title("aaaa测试"+"\t"+new SimpleDateFormat("yyyy-MM-dd").format(new Date()))
                    .description("docker-compose")
                    .version("1.0")
                    .termsOfServiceUrl("https://www.atguigu.com/")
                    .build();
        }
    
    }
    
  2. entity

    user.java

    package com.wang.docker.entities;
    
    import java.io.Serializable;
    import java.util.Date;
    import javax.persistence.*;
    
    @Table(name = "t_user")
    public class User implements Serializable {
        @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.java

    package com.wang.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;
    /**
     * @ClassName: UserDTO
     * @Description
     * @Version 1.0
     */
    @AllArgsConstructor
    @NoArgsConstructor
    @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 +
                    '}';
        }
    }
    
    
  3. mapper

    UserMapper.java

    package com.wang.docker.mapper;
    
    import com.wang.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.wang.docker.mapper.UserMapper">
      <resultMap id="BaseResultMap" type="com.wang.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>
    
  4. service

    UserService.java

    package com.wang.docker.service;
    
    import com.wang.docker.entities.User;
    import com.wang.docker.mapper.UserMapper;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    /**
     * @ClassName: UserService
     * @Description
     * @Version 1.0
     */
    @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;
        }
    }
    
    
  5. controller

    UserController.java

    package com.wang.docker.controller;
    
    import cn.hutool.core.util.IdUtil;
    import com.wang.docker.entities.User;
    import com.wang.docker.service.UserService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import java.util.Random;
    
    /**
     * @ClassName: UserController
     * @Description
     * @Author:我自己
     * @Date: 2022/8/6  16:16
     * @Version 1.0
     */
    @RestController
    @Api(description = "用户User接口")
    @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("wfc"+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.findUserById(id);
        }
    
    }
    
    

打包

maven打包上传至服务器的/mydocker目录下

编写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

构建镜像

docker build -t zzyy_docker:1.6 .

不使用Compose调试

  1. 启动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
    
  2. 进入容器创建boot_docker数据库

    docker exec -it mysql57 /bin/bash
    mysql -uroot -p123456
    create database boot_docker;
    use boot_docker;
    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='用户表';
    
  3. 启动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
    
  4. 本地启动主启动类程序测试

    http://localhost:6001/swagger-ui.html#/
    

    在这里插入图片描述

    执行两个测试接口均正常,可以读写到mysql数据并且redis内数据正常。

  5. 微服务容器

    docker run -d -p 6001:6001 zzyy_docker:1.6
    
  6. 访问微服务

    http://192.168.10.101:6001/swagger-ui.html#/
    

    swagger页面、接口均正常。

上述过程运行成功。但是存在以下几个问题:

  • 先后顺序要求固定,先mysql+redis,后微服务
  • 多个run命令需要启动容器
  • 容器间的启停或宕机有可能导致IP地址对应容器变化,导致服务异常。可以使用自定义网络通过域名进行解决。

接下来通过使用compose解决上述问题。

使用Compose调试

  1. 在mycompose目录下创建docker-compose.yml

    version: "3"
    
     
    
    services:
    
      microService:
    
        image: zzyy_docker:1.7
    
        container_name: ms01
    
        ports:
    
          - "6001:6001"
    
        volumes:
    
          - /app/microService:/data
    
        networks: 
    
          - atguigu_net 
    
        depends_on: 
    
          - redis
    
          - mysql
    
     
    
      redis:
    
        image: redis:6.0.8
    
        ports:
    
          - "6379:6379"
    
        volumes:
    
          - /app/redis/redis.conf:/etc/redis/redis.conf
    
          - /app/redis/data:/data
    
        networks: 
    
          - atguigu_net
    
        command: redis-server /etc/redis/redis.conf
    
     
    
      mysql:
    
        image: mysql:5.7
    
        environment:
    
          MYSQL_ROOT_PASSWORD: '123456'
    
          MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
    
          MYSQL_DATABASE: 'db2021'
    
          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.d
    
        networks:
    
          - atguigu_net
    
        command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
    
     
    
    networks: 
    
       atguigu_net: 
    
  2. 修改docker_boot中application.yaml文件,主要将IP换为服务名称。通过服务名访问,与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.10.101:3306/boot_docker?useUnicode=true&characterEncoding=utf-8&useSSL=false
    spring.datasource.url=jdbc:mysql://mysql:3306/boot_docker?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.10.101
    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.wang.docker.entities
    # ========================swagger=====================
    spring.swagger2.enled=true
    
    

    重新打包上传服务器的mycompose目录

  3. 在mycompose目录下编写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
    
  4. 构建镜像

    docker build -t zzyy_docker:1.7 .
    
  5. 通过compose启动各个容器

    docker compose up
    #后台
    docker compose up -d
    
  6. 进入mysql容器新建数据库和表

    docker exec -it 容器实例id /bin/bash
    mysql -uroot -p
    create database boot_docker;
    use boot_docker;
    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. 测试通过

  8. 停止

    docker compose stop
    

WordPress测试验证增量更新

在这里插入图片描述

不用compose

#创建网络
docker network create blog

#启动mysql
docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=wordpress \
-v /app/mysql-data:/var/lib/mysql \
-v /app/myconf:/etc/mysql/conf.d \
--restart always --name mysql \
--network blog \
mysql:8.0

docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=wordpress \
-v mysql-data:/var/lib/mysql \
-v /app/myconf:/etc/mysql/conf.d \
--restart always --name mysql \
--network blog \
mysql:8.0

#启动wordpress
docker run -d -p 8080:80 \
-e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=123456 \
-e WORDPRESS_DB_NAME=wordpress \
-v wordpress:/var/www/html \
--restart always --name wordpress-app \
--network blog \
wordpress:latest

使用compose

name: myblog
services:
  mysql:
    container_name: mysql
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=wordpress
    volumes:
      - mysql-data:/var/lib/mysql
      - /app/myconf:/etc/mysql/conf.d
    restart: always
    networks:
      - blog

  wordpress:
    image: wordpress
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_USER: root
      WORDPRESS_DB_PASSWORD: 123456
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress:/var/www/html
    restart: always
    networks:
      - blog
    depends_on:
      - mysql

volumes:
  mysql-data:
  wordpress:

networks:
  blog:

特点:

  • 增量更新(修改8080为80重新启动)

    • 修改 Docker Compose 文件。重新启动应用。只会触发修改项的重新启动。
  • 数据不删

    • 默认就算down了容器,所有挂载的卷不会被移除。比较安全

强制删除数据卷:

docker compose -f compose.yaml down --rmi all -v

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/714317.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CloudFlare 里如何设置参数传递的 301 重定向

自从接到【哈哈,笑死我了都,黔驴技穷了都!】一文里提到的代维客户订单,这两天明月就一直在加班加点的重新部署着客户的四个服务器,因为有三个都是 WordPress+WooCommerce 式的电商平台,很是有些费时费力,好在现在基本都搞定了,剩下的就是些细节方面的优化、调整了。期间…

2024 年最新 Python 使用 gewe 框架搭建微信机器人实现语音智能回复(详细教程)

Gewe 个微框架 GeWe&#xff08;个微框架&#xff09;是一个创新性的软件开发框架&#xff0c;专注于IPAD协议&#xff0c;为个人微信号以及企业信息安全提供了强大的功能和保障。GeWe的设计旨在简化开发过程&#xff0c;使开发者能够高效、灵活地构建和定制通信协议&#xff…

uniapp实现路由拦截——实战案例(二)

uniapp如何实现登录路由拦截&#xff1f; 今天再次介绍一下 uni-simple-router 插件&#xff0c;记得最初使用时&#xff0c;是在三年以前了&#xff0c;这里简单介绍通过自动读取 pages.json 作为路由表的方式&#xff0c;欢迎指教~ 文章目录 uniapp如何实现登录路由拦截&…

哪些数据管理知识领域需要做到数据全生命周期管理

一、数据生命周期 数据管理、数据治理、数据安全、元数据管理、数据治理等知识领域,都需要按照数据的生命周期开展管理工作。数据生命周期包括计划、设计/启用、创建/获取、存储/维护、使用、增强和处置。详见下图。 1.数据治理生命周期 1)规划:将数据要求与业务战略连接起…

关于小程序测试账号如何移除

关于小程序测试账号如何移除 有很多小伙伴一开始做开发,一开始用来做测试号,登录微信公众号的时候会提示配置项, 那么如何移除掉呢 https://mp.weixin.qq.com/ 关注「公众平台安全助手」公众号 -> 绑定查询 -> 微信号绑定账号 -> 小程序 -> 点击小程序 -> 解除…

ByteTrack

1. 论文中伪代码表示的流程图 2. 简要版 此图源自&#xff1a; ByteTrack多目标跟踪原理&#xff0c;白老师人工智能学堂 3. 详细版 根据ByteTrack-CPP-ncnn代码的数据流画的较为详细的流程图&#xff1a; 4. ByteTrack-CPP-ncnn的UML类图 Reference ByteTrack多目标跟踪原…

Qt状态机框架

概述 状态机框架提供了用于创建和执行状态图的类。这些概念和符号基于Harel的Statecharts:复杂系统的可视化形式(http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf)&#xff0c;也是UML状态图的基础。状态机执行的语义基于状态图XML (SCXML)(http://…

消息队列-分布式消息队列技术选型

Kafka Kafka 是 LinkedIn 开源的一个分布式流式处理平台&#xff0c;已经成为 Apache 顶级项目&#xff0c;早期被用来用于处理海量的日志&#xff0c;后面才慢慢发展成了一款功能全面的高性能消息队列。 流式处理平台具有三个关键功能&#xff1a; 消息队列&#xff1a;发布和…

SQLServer使用 PIVOT 和 UNPIVOT行列转换

在SQL Server中&#xff0c;PIVOT是一个用于将行数据转换为列数据的操作。它特别适用于将多个行中的值转换为多个列的情况&#xff0c;并在此过程中执行聚合操作。以下是关于SQL Server中PIVOT操作的详细解释和示例&#xff1a; 1、本文内容 概述语法备注关键点简单 PIVOT 示…

Linux命令2

文章目录 移动文件或目录mv格式 查找命令/文件存放位目录置which格式 查找文件或目录find格式查找类型多个查找条件逻辑运算符 移动文件或目录 mv 将文件或者目录移动到指定的位置 如果目标的位置和源位置相同&#xff0c;相当于改名操作 跨目录移动相当于window的剪切 格式…

MacOS之解决:开盖启动问题(七十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

2024.6.16周报

目录 摘要 ABSTRACT 一、文献阅读 一、题目 二、摘要 三、创新点 四、模型架构 五、文章解读 1、Introduction 2、实验 3、结论 二、代码复现 1、模型代码 2、实验结果 三、总结 摘要 本周我阅读了一篇题目为《Contaminant Transport Modeling and Source Att…

工厂方法模式实战之某商场一次促销活动

目录 1.5.1、前言1.5.2、实战场景简介1.5.3、开发环境1.5.4、用传统的if-else语句实现1.5.4.1、工程结构1.5.4.2、if-else需求实现1.5.4.3、测试验证 1.5.5、工厂模式优化代码1.5.5.1、工程结构1.5.5.2、代码实现1.5.5.2.1、定义各种商品发放接口及接口实现1.5.5.2.2、定义工厂…

项目经理,请勇敢Say No~

为什么要say no&#xff1f; 培养say no的勇气 优雅的say no&#xff01; say no 三部曲&#xff0c;项目经理&#xff0c;你准备好了吗&#xff1f; 为什么要say no&#xff1f; 保护项目完整性的屏障 项目管理的核心在于平衡时间、成本与质量三大要素&#xff0c;任何一项的…

STL——set、map、multiset、multimap的介绍及使用

文章目录 关联式容器键值对树形结构与哈希结构setset的介绍set的使用set的模板参数列表set的构造set的使用set的迭代器使用演示 multisetmultiset演示 mapmap的定义方式map的插入map的查找map的[ ]运算符重载map的迭代器遍历multimapmultimap的介绍multimap的使用 在OJ中的使用…

全球“抱团”美股,美股“抱团”AI

内容提要 过去一个月内&#xff0c;全球约有300亿美元新资金流入股票基金&#xff0c;其中高达94%投向了美国资产&#xff1b;一季度&#xff0c;海外投资者购入了1870亿美元美国公司债券&#xff0c;同比增长61%。 文章正文 尽管美国面临债务问题和大选带来的政治分歧&#…

索引-定义、创建(CREATE INDEX)、删除(DROP INDEX)

一、概述 1、索引是SQL语言定义的一种数据对象&#xff0c;是大多数DBMS为数据库中基本表创建的一种辅助存取结构&#xff0c;用于响应特定查询条件进行查询时的查询速度&#xff0c;DBMS根据查询条件从数据库文件中&#xff0c;选择出一条或者多条数据记录以供检索&#xff0…

【JS重点17】原型继承

目录 一&#xff1a;什么是原型继承 二&#xff1a;通过赋值方式实现原型继承 三&#xff1a;通过构造函数实现原型继承 四&#xff1a;如何赚钱 一&#xff1a;什么是原型继承 通过往构造函数上的原型对象添加属性和方法&#xff0c;再new一个实例对象&#xff0c;从而实例…

18. 第十八章 继承

18. 继承 和面向对象编程最常相关的语言特性就是继承(inheritance). 继承值得是根据一个现有的类型, 定义一个修改版本的新类的能力. 本章中我会使用几个类来表达扑克牌, 牌组以及扑克牌性, 用于展示继承特性.如果你不玩扑克, 可以在http://wikipedia.org/wiki/Poker里阅读相关…

CSS期末复习速览(二)

1.元素显示模式分为三种&#xff1a;块元素&#xff0c;行内元素&#xff0c;行内块元素 2.块元素&#xff1a;常见的块元素&#xff1a;<h1>~<h6> <p> <div> <ul> <ol> <li>&#xff0c;特点&#xff1a;自己独占一行&a…