基于docker的test-containers环境百宝箱
在很多时候,程序猿们更关注代码本身,而不愿意把时间花费在环境搭建上,这也是Docker变得越来越受欢迎的原因之一。test-containers
是Docker生态圈中的一颗新星,其 主要针对测试领域、背靠Docker实现环境百宝箱功能
。
test-containers: 你要的环境,我都有~
假设我们现在需要一个redis-cluster环境来学习reids pipeline相关的代码知识,那么就需要搭建一套redis集群:
环境支持方式 | 直接搭建 | docker搭建 | 使用test-container |
---|---|---|---|
工作量(简单预估) | 100个单位 | 30个单位 | 15个单位 |
test-container环境支持(示例):
提示一 : test-container基于Docker,使用test-container前需要安装Docker环境。
提示二 : test-container提供的环境不能应用于生产、只能用于测试环境等场景。
使用test-container提供单机redis:
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName;/*** 单机redis环境支持** @author {@link JustryDeng}* @since 2020/11/13 16:14:18*/ @Slf4j @Testcontainers @Import(value = {ExcludedAllAutoConfiguration.class, RedisAutoConfiguration.class}) @ContextConfiguration(initializers = RedisStandaloneEnvSupport .Initializer.class) public class RedisStandaloneEnvSupport implements RedisEnvSupport {/** 标准的docker镜像(即${镜像名}:${tag名}) */private static final String DOCKER_IMAGE_NAME = "redis:5.0.3-alpine";/** docker开启的端口 */private static final int CONTAINER_PORT = 6379;@Containerpublic static GenericContainer<?> redisContainer = new GenericContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME)).withExposedPorts(CONTAINER_PORT);/*** init application context** @author {@link JustryDeng}* @since 2020/11/14 19:22:23*/public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) {String redisIpAddress = redisContainer.getContainerIpAddress();log.info("redisIpAddress is [{}]", redisIpAddress);System.setProperty("spring.redis.host", redisIpAddress);Integer redisPort = redisContainer.getMappedPort(CONTAINER_PORT);log.info("redisPort is [{}]", redisPort);Assert.assertNotNull("redisPort is null", redisPort);System.setProperty("spring.redis.port", redisPort.toString());}}}
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.redis.RedisStandaloneEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate;import javax.annotation.Resource; import java.time.Duration; import java.util.concurrent.TimeUnit;/*** 测试** @author {@link JustryDeng}* @since 2020/11/13 16:36:21*/ @Slf4j @SpringBootTest public class RedisStandaloneTest extends RedisStandaloneEnvSupport {@ResourceStringRedisTemplate stringRedisTemplate;@Testvoid one() throws InterruptedException {String name = stringRedisTemplate.opsForValue().get("name");System.err.println(name);Assert.assertNull(name);String justryDeng = "JustryDeng";stringRedisTemplate.opsForValue().set("name", justryDeng, Duration.ofSeconds(3));name = stringRedisTemplate.opsForValue().get("name");System.err.println(name);Assert.assertEquals(justryDeng, name);TimeUnit.SECONDS.sleep(3);name = stringRedisTemplate.opsForValue().get("name");System.err.println(name);Assert.assertNull(name);}}
输出
使用test-container提供集群redis:
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.redis.helper.ClientResources4Test; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.FixedHostPortGenericContainer; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers;/*** redis集群环境支持** @author {@link JustryDeng}* @since 2020/11/13 16:14:18*/ @Slf4j @Testcontainers @Import(value = {ExcludedAllAutoConfiguration.class, ClientResources4Test.class, RedisAutoConfiguration.class}) @ContextConfiguration(initializers = RedisClusterEnvSupport.Initializer.class) public class RedisClusterEnvSupport implements RedisEnvSupport {/** 标准的docker镜像(即${镜像名}:${tag名}) */private static final String DOCKER_IMAGE_NAME = "grokzen/redis-cluster:6.0.7";/*** 集群最好用FixedHostPortGenericContainer, 主动避免端口冲突即可*/@Container@SuppressWarnings("deprecation")public static GenericContainer<?> redisContainer = new FixedHostPortGenericContainer<>(DOCKER_IMAGE_NAME).withFixedExposedPort(7000, 7000).withFixedExposedPort(7001, 7001).withFixedExposedPort(7002, 7002).withFixedExposedPort(7003, 7003).withFixedExposedPort(7004, 7004).withFixedExposedPort(7005, 7005);/*** init application context** @author {@link JustryDeng}* @since 2020/11/14 19:22:23*/public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) {String redisIpAddress = redisContainer.getContainerIpAddress();String nodesInfo = redisIpAddress + ":" + 7000+ "," + redisIpAddress + ":" + 7001+ "," + redisIpAddress + ":" + 7002+ "," + redisIpAddress + ":" + 7003+ "," + redisIpAddress + ":" + 7004+ "," + redisIpAddress + ":" + 7005;log.info("spring.redis.cluster.nodes is [{}]", nodesInfo);System.setProperty("spring.redis.cluster.nodes", nodesInfo);}} }
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.redis.RedisClusterEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate;import javax.annotation.Resource; import java.time.Duration; import java.util.concurrent.TimeUnit;/*** 测试** @author {@link JustryDeng}* @since 2020/11/13 16:36:21*/ @Slf4j @SpringBootTest public class RedisClusterTest extends RedisClusterEnvSupport {@ResourceStringRedisTemplate stringRedisTemplate;@Testvoid one() throws InterruptedException {String name = stringRedisTemplate.opsForValue().get("name");System.err.println(name);Assert.assertNull(name);String justryDeng = "JustryDeng";stringRedisTemplate.opsForValue().set("name", justryDeng, Duration.ofSeconds(3));name = stringRedisTemplate.opsForValue().get("name");System.err.println(name);Assert.assertEquals(justryDeng, name);TimeUnit.SECONDS.sleep(3);name = stringRedisTemplate.opsForValue().get("name");System.err.println(name);Assert.assertNull(name);}}
输出
使用test-container提供MySQL:
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.utility.DockerImageName;/*** Mysql8环境支持** @author {@link JustryDeng}* @since 2020/11/17 14:14:43*/ @Slf4j @ContextConfiguration(initializers = Mysql8EnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class, DataSourceAutoConfiguration.class}) public class Mysql8EnvSupport implements MysqlEnvSupport{/** 标准的docker镜像(即${镜像名}:${tag名}) */private static final String DOCKER_IMAGE_NAME = "mysql:8.0.22";/** 数据库 */ private static final String DATABASE = "mine_database";/** 连接池类型 */ private static final Class<?> POOL_TYPE_CLASS = HikariDataSource.class;@ClassRule public static MySQLContainer<?> mySqlContainer = new MySQLContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME)).withDatabaseName(DATABASE)// 初始化脚本.withInitScript("mysql/init_mysql.sql")/// 配置文件///.withConfigurationOverride("mysql/config");/*** init application context** @author {@link JustryDeng}* @since 2020/11/14 19:22:23*/ public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) {// startmySqlContainer.start();String jdbcUrl = mySqlContainer.getJdbcUrl();int endIndex = jdbcUrl.indexOf("?");String additionalSetting = "?characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";if (endIndex < 0) {jdbcUrl = jdbcUrl + additionalSetting;} else {jdbcUrl = jdbcUrl.substring(0, endIndex) + additionalSetting;}System.setProperty("spring.datasource.url", jdbcUrl);System.setProperty("spring.datasource.username", mySqlContainer.getUsername());System.setProperty("spring.datasource.password", mySqlContainer.getPassword());System.setProperty("spring.datasource.driver-class-name", mySqlContainer.getDriverClassName());System.setProperty("spring.datasource.type", POOL_TYPE_CLASS.getName());} }}
基类中涉及到的脚本的位置及内容为
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.mysql.Mysql8EnvSupport; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource; import java.util.List; import java.util.Map;/*** 测试** @author {@link JustryDeng}* @since 2020/11/13 16:36:21*/ @Slf4j @SpringBootTest public class Mysql8Test extends Mysql8EnvSupport {@ResourceTestMapper testMapper;@Testvoid one() {System.err.println(testMapper.count());List<Map<String, Object>> x = testMapper.selectAll();System.err.println(x);}@Mapperpublic interface TestMapper {@Select("select count(*) from employee")int count();@Select("select * from employee")List<Map<String, Object>> selectAll();}}
输出
使用test-container提供pgSQL:
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.utility.DockerImageName;/*** PostgreSql10环境支持** @author {@link JustryDeng}* @since 2020/11/17 21:14:29*/ @Slf4j @ContextConfiguration(initializers = PostgreSql10EnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class, DataSourceAutoConfiguration.class}) public class PostgreSql10EnvSupport implements PostgreSqlEnvSupport {/** 标准的docker镜像(即${镜像名}:${tag名}) */private static final String DOCKER_IMAGE_NAME = "postgres:10.15";/** 数据库 */private static final String DATABASE = "mine_database";/** 连接池类型 */private static final Class<?> POOL_TYPE_CLASS = HikariDataSource.class;@ClassRulepublic static PostgreSQLContainer<?> pgSqlContainer = new PostgreSQLContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME)).withDatabaseName(DATABASE)// 初始化脚本.withInitScript("postgresql/init_postgresql.sql");/*** init application context** @author {@link JustryDeng}* @since 2020/11/14 19:22:23*/public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) {// startpgSqlContainer.start();System.setProperty("spring.datasource.url", pgSqlContainer.getJdbcUrl());System.setProperty("spring.datasource.username", pgSqlContainer.getUsername());System.setProperty("spring.datasource.password", pgSqlContainer.getPassword());System.setProperty("spring.datasource.driver-class-name", pgSqlContainer.getDriverClassName());System.setProperty("spring.datasource.type", POOL_TYPE_CLASS.getName());}}}
基类中涉及到的脚本的位置及内容为
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.postgresql.PostgreSql10EnvSupport; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource; import java.util.List; import java.util.Map;/*** 测试** @author {@link JustryDeng}* @since 2020/11/13 16:36:21*/ @Slf4j @SpringBootTest public class PostgreSql10Test extends PostgreSql10EnvSupport {@ResourceTestMapper testMapper;@Testvoid one() {System.err.println(testMapper.count());System.err.println(testMapper.selectAll());}@Mapperpublic interface TestMapper {@Select("select count(*) from employee")int count();@Select("select * from employee")List<Map<String, Object>> selectAll();}}
输出
使用test-container提供Kafka:
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.kafka.annotation.EnableKafka; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.KafkaContainer; import org.testcontainers.utility.DockerImageName;/*** 一个简单的kafka环境支持** @author {@link JustryDeng}* @since 2020/11/18 12:11:54*/ @Slf4j @EnableKafka @ContextConfiguration(initializers = KafkaSimpleEnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class, KafkaAutoConfiguration.class}) public class KafkaSimpleEnvSupport implements KafkaEnvSupport {/** 标准的docker镜像(即${镜像名}:${tag名}) */private static final String DOCKER_IMAGE_NAME = "confluentinc/cp-kafka:5.4.3";@ClassRulepublic static KafkaContainer kafkaContainer = new KafkaContainer(DockerImageName.parse(DOCKER_IMAGE_NAME));/*** init application context** @author {@link JustryDeng}* @since 2020/11/14 19:22:23*/public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) {// startkafkaContainer.start();String bootstrapServers = kafkaContainer.getBootstrapServers();System.setProperty("spring.kafka.bootstrap-servers", bootstrapServers);// 因为是测试环境, 这里用earliest, 以避免在没有提交offset情况下,用latest不会读取旧数据的问题System.setProperty("spring.kafka.consumer.auto-offset-reset", "earliest");}} }
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.kafka.KafkaSimpleEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.core.KafkaTemplate;import javax.annotation.Resource; import java.util.UUID; import java.util.concurrent.TimeUnit;/*** 测试** @author {@link JustryDeng}* @since 2020/11/18 12:15:47*/ @Slf4j @SpringBootTest @Import(value = {KafkaSimpleTest.MyConsumer.class, KafkaSimpleTest.MyProducer.class}) public class KafkaSimpleTest extends KafkaSimpleEnvSupport {static final String TOPIC_NAME4TEST = "my-topic4test";@ResourceMyProducer myProducer;@Testvoid one() throws InterruptedException {// 生产消息for (int i = 0; i < 10; i++) {myProducer.sendMessage("邓沙利文-" + i);}// sleep几秒,以便观察消费者是否消费消息TimeUnit.SECONDS.sleep(3);Assert.assertTrue("消费消息失败(或消费消息超时)", MyConsumer.hasConsumedMsg);}/*** 生产者*/@Slf4jpublic static class MyProducer {@Resourceprivate KafkaTemplate<String, String> kafkaTemplate;public void sendMessage(String message) {kafkaTemplate.send(TOPIC_NAME4TEST, "key-" + UUID.randomUUID().toString(), message);}}/*** 消费者*/@SuppressWarnings("unused")@Slf4jpublic static class MyConsumer {/** 是否已经消费了消息 */static boolean hasConsumedMsg = false;@KafkaListener(topics = TOPIC_NAME4TEST, groupId = "group-b")public void consumerOne(String message) {log.info("consumerOne消费了消息 [{}]", message);hasConsumedMsg = true;}} }
输出
使用test-container提供RabbitMQ:
环境基类
import com.niantou.testcontainer.ExcludedAllAutoConfiguration; import com.niantou.testcontainer.author.JustryDeng; import lombok.extern.slf4j.Slf4j; import org.junit.ClassRule; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.containers.RabbitMQContainer;/*** 一个简单的RabbitMQ环境支持** @author {@link JustryDeng}* @since 2020/11/20 12:49:45*/ @Slf4j @ContextConfiguration(initializers = RabbitMqSimpleEnvSupport.Initializer.class) @Import(value = {ExcludedAllAutoConfiguration.class}) public class RabbitMqSimpleEnvSupport {/** 标准的docker镜像(即${镜像名}:${tag名}) */private static final String DOCKER_IMAGE_NAME = "rabbitmq:management-alpine";@ClassRulepublic static RabbitMQContainer rabbitMqContainer = new RabbitMQContainer(DOCKER_IMAGE_NAME).withAdminPassword("ds123");/*** init application context** @author {@link JustryDeng}* @since 2020/11/14 19:22:23*/public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(@SuppressWarnings("NullableProblems") ConfigurableApplicationContext configurableApplicationContext) {// startrabbitMqContainer.start();String host = rabbitMqContainer.getHost();log.info("spring.rabbitmq.host={}", host);System.setProperty("spring.rabbitmq.host", host);Integer amqpPort = rabbitMqContainer.getAmqpPort();log.info("spring.rabbitmq.port={}", amqpPort);System.setProperty("spring.rabbitmq.port", String.valueOf(amqpPort));String adminUsername = rabbitMqContainer.getAdminUsername();log.info("spring.rabbitmq.username={}", adminUsername);System.setProperty("spring.rabbitmq.username", adminUsername);String adminPassword = rabbitMqContainer.getAdminPassword();log.info("spring.rabbitmq.password={}", adminPassword);System.setProperty("spring.rabbitmq.password", adminPassword);}}}
测试类
import com.niantou.testcontainer.author.JustryDeng; import com.niantou.testcontainer.rabbitmq.RabbitMqSimpleEnvSupport; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.Test; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.DirectExchange; import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import;import javax.annotation.Resource; import java.util.concurrent.TimeUnit;import static com.niantou.testcontainer.rabbitmq.test.RabbitMqSimpleTest.MyConfig.MY_EXCHANGE_NAME; import static com.niantou.testcontainer.rabbitmq.test.RabbitMqSimpleTest.MyConfig.QUEUE_NAME; import static com.niantou.testcontainer.rabbitmq.test.RabbitMqSimpleTest.MyConfig.ROUTING_KEY;/*** 测试** @author {@link JustryDeng}* @since 2020/11/18 12:15:47*/ @Slf4j @SpringBootTest @Import(value = {RabbitMqSimpleTest.MyConsumer.class, RabbitMqSimpleTest.MyProducer.class,RabbitMqSimpleTest.MyConfig.class}) public class RabbitMqSimpleTest extends RabbitMqSimpleEnvSupport {@ResourceMyProducer myProducer;@Testvoid one() throws InterruptedException {// 生产消息for (int i = 0; i < 10; i++) {myProducer.sendMessage("邓沙利文-" + i);}// sleep几秒,以便观察消费者是否消费消息TimeUnit.SECONDS.sleep(3);Assert.assertTrue("消费消息失败(或消费消息超时)", MyConsumer.hasConsumedMsg);}/*** 配置类*/@Slf4jpublic static class MyConfig {static final String ROUTING_KEY = "myRoutingKey";static final String QUEUE_NAME = "my-queue";static final String MY_EXCHANGE_NAME = "my-direct-exchange";@Beanpublic Queue myQueue() {return new Queue(QUEUE_NAME);}@Beanpublic DirectExchange myDirectExchange() {return new DirectExchange(MY_EXCHANGE_NAME);}@Beanpublic Binding myBinding(Queue myQueue, DirectExchange myDirectExchange) {return BindingBuilder.bind(myQueue).to(myDirectExchange).with(ROUTING_KEY);}}/*** 生产者*/@Slf4jpublic static class MyProducer {@Resourceprivate AmqpTemplate amqpTemplate;public void sendMessage(String message) {amqpTemplate.convertAndSend(MY_EXCHANGE_NAME, ROUTING_KEY, message);}}/*** 消费者*/@Slf4jpublic static class MyConsumer {/** 是否已经消费了消息 */static boolean hasConsumedMsg = false;@SuppressWarnings("unused")@RabbitListener(queues = QUEUE_NAME)public void consumerOne(String message) {log.info("consumerOne消费了消息 [{}]", message);hasConsumedMsg = true;}} }
输出
test-containers,初步学习完毕!
^_^ 如有不当之处,欢迎指正
^_^ 参考链接
https://www.testcontainers.org/
^_^ 测试代码托管链接
https://github.com/JustryDeng…test-containers
^_^ 本文已经被收录进《程序员成长笔记》 ,笔者JustryDeng
基于docker的test-containers环境百宝箱相关推荐
- 基于Docker的深度学习环境NVIDIA和CUDA部署以及WSL和linux镜像问题
基于Docker的深度学习环境部署 1. 什么是Docker? 2. 深度学习环境的基本要求 3. Docker的基本操作 3.1 在Windows上安装Docker 3.2 在Ubuntu上安装Do ...
- mac启动本地redis_通过 Laravel Sail 构建基于 Docker 的本地开发环境
Laravel 官方最近发布了 Laravel Sail -- 一个轻量级的.基于 Docker 的 Laravel 本地集成开发环境,今天学院君就以 Mac 系统为例,给大家演示下如何基于 Lara ...
- docker容器管理 php,基于Docker的PHP开发环境
[编者的话]本文作者是Geoffrey,他是一个PHP的Web开发者,喜欢DevOps和Docker.本文主要介绍了如何使用Docker构建PHP的开发环境,文中作者也探讨了构建基于Docker的开发 ...
- ubuntu18.04中基于Docker搭建tensorflow-gpu开发环境
前提条件就不多提啦,首先得装好nvidia驱动和Docker19以上版本,网上有很多教程. 尝试1:拉取现有的deepo镜像制作 deepo是一个囊括几乎所有深度学习框架的开源镜像,这里我们选择拉取一 ...
- 基于Docker的Python开发
作者|GUEST 编译|VK 来源|Analytics Vidhya 在PyCharm和Visual Studio代码上支持CUDA 介绍 如果你没有经验,建立一个开发环境是不容易的,特别是如果你想学 ...
- DNMP:基于docker搭建集成LNMP(nginx+mysql+php)
有一天,主机商跑路了.迫于无奈之下,我需要进行数据迁移.原先用的主机我可以什么都不管,直接用就行.而现在,只有一个centos服务器.一切从零开始... 我曾试过一个一个安装,从docker入手,一步 ...
- 基于docker的 Hyperledger Fabric 多机环境搭建(上)
环境:ubuntu 16.04 Docker 17.04.0-ce go 1.7.4 consoul v0.8.0.4 ======================================= ...
- 基于docker在Ubuntu上搭建TensorFlow-GPU计算环境
这里转载一篇Docker安装TF GPU的版本 基于docker在Ubuntu上搭建TensorFlow-GPU计算环境 由于实验室的服务器有多人共享使用,而不同人的代码对应的keras和tensor ...
- Docker入门指南:基于 docker 搭建机器学习/深度学习开发环境
实际工作中,许多项目开发需要在Linux服务器上进行,本文为习惯使用 Windows 操作系统的朋友介绍一种基于Docker的,跨平台.便携性(方便移植.重新部署.可远程访问)的开发环境搭建方法. 1 ...
- 【K8S】基于Docker+K8S+GitLab/SVN+Jenkins+Harbor搭建持续集成交付环境(环境搭建篇)
写在前面 最近在 K8S 1.18.2 版本的集群上搭建DevOps环境,期间遇到了各种坑.目前,搭建环境的过程中出现的各种坑均已被填平,特此记录,并分享给大家! 服务器规划 IP 主机名 节点 操作 ...
最新文章
- H5用户地址位置选择地点获取经纬度(效果图)
- WPF学习拾遗(二)TextBlock换行
- 本科4篇顶会!清华特奖高天宇干货分享:我是这样写论文、做实验、与导师相处...
- 2dx解析cocosbuilder中使用layer时的缺陷
- linux运维实战练习-2015年9月13日-9月15日课程作业(练习)安排
- 下面代码打印的结果?
- Product Archive相关的标准function module
- html版本操作手册,全新HTML5用户手册(版本2017)–互联网股票买卖操作.PDF
- TODA-MES电池行业解决方案
- Java实现下载url视频资源
- 被反爬虫搞到心态崩溃
- Mac 安装非信任开发者软件
- unity 彩带粒子_unity游戏缤纷五彩纸屑粒子特效Confetti FX 1.0
- [译] 改善 DaVinci Resolve 性能的 5 个秘诀
- thinkpad x250装黑苹果教程_ThinkPad E450c 傻瓜式黑苹果一键安装教程
- Elasticsearch常见报错和处理方法
- java bigdecimal 开方_JAVA BigDecimal使用牛顿迭代法计算平方根(开方)
- 访客模式 无痕模式 区别_旧访客设计模式的新生活
- HTML5 drag和drop的亲手实践
- android照片美颜项目_照片美颜p图编辑app下载
热门文章
- python实验报告代写_Python 读写CSV作业代写代做、代写Python I/O文件读写程序作业、代写代做python 实验报告...
- jQuery插件库常用前端库引用地址详细提供
- java spi 热插拔_利用SPI机制实现责任链模式中的处理类热插拔
- 《孙子兵法》的优秀读后感作文2100字
- 【AI创新者】云知声梁家恩:当 AI 遇见 IoT——云知声的 AI 之路
- Python发送电子邮件.
- 面试HR常问的几个问题?
- python 操作word页眉表格_Python 如何对word文档(.docx)的页眉和页脚进行编辑?
- java做一个查询网页版_用java写一个网页输入url点击查询即可在下面显示网页源代码...
- Android关于BottomNavigationView效果实现指南