原文:What is Docker? Learn How to Use Containers – Explained with Examples,作者:Sebastian Sigl

容器是当今软件开发的一个重要工具。当你利用容器时,在任何环境中运行应用程序都变得很容易。

运行容器的最流行技术是 Docker,它可以在任何操作系统上运行。

在这篇博文中,你将学习 Docker 最基本的 3 个用例:

  • 使用 Docker 在本地运行一个数据库
  • 使用 Docker 化的数据库运行自动测试
  • 使用 Docker 在本地和生产中运行你的应用程序

你将使用一个 Java Spring Boot 应用程序,但所有学习内容都适用于你选择的其他任何编程语言。

为了运行所有的例子,你需要:

使用 Docker 为运行应用程序提供独立环境

Docker 减少了重复的、无意义的配置任务,并在整个开发生命周期中用于快速、简单和可移植的应用开发——桌面和云。(源自:https://www.docker.com/use-cases/

Docker 的超能力的核心是利用所谓的 cgroups 来创建轻量级的、隔离的、可移植的和高性能的环境,你可以在几秒钟内启动。

让我们来看看你如何使用 Docker 来提高生产力。

Database 容器

使用 Docker,你可以在几秒钟内启动许多类型的数据库。这很容易,而且不会因为你运行数据库所需的其他要求而污染你的本地系统。一切都与 Docker 容器打包在一起。

通过在 hub.docker.com 搜索,你可以为许多数据库找到现成的容器。

使用docker run命令,你可以启动一个 MySQL 的容器

docker run --rm -v "$PWD/data":/var/lib/mysql --name mysql -e MYSQL_ROOT_PASSWORD=admin-password -e MYSQL_DATABASE=my-database -p 3306:3306 mysql:8.0.28-debian

该命令使用了运行 Docker 容器的高级功能:

  • -v "$PWD/data" 映射了你的本地目录./data到 Docker 容器,这使你能够启动Docker容器而不丢失你的数据
  • -p 3306:3306 映射容器的 3306 端口到我们的机器的 3306 端口上,以便其他应用程序可以使用它
  • -e MYSQL_DATABASE=my-database 设置一个环境变量,自动创建一个名为my-database的新数据库
  • -e MYSQL_ROOT_PASSWORD=admin-password 设置一个环境变量来设置管理密码
  • --rm 停止时移除容器

这些环境变量和更多的环境变量都记录在 Docker镜像的页面

如何使用数据库容器进行开发

你将使用一个流行的技术栈来构建,一个基于JavaSpring Boot 的 Web 应用程序。为了专注于 Docker 部分,你可以从官方的 用Rest指南访问JPA数据 克隆一个简单的演示应用程序。

#下载示例应用程序
git clone https://github.com/spring-guides/gs-accessing-data-rest.git

#打开最终的应用程序文件夹
cd complete

该应用程序自带一个内存数据库,这对生产来说没有价值,因为它不允许多个服务访问和修改(mutate)一个数据库。一个MySQL数据库更适合于将你的应用程序扩展到更多的读和写。

因此,将 MySQL 驱动添加到你的 pom.xml 文件:

       <!-- Disable in memory database -->
       <!--
       <dependency>
           <groupId>com.h2database</groupId>
           <artifactId>h2</artifactId>
           <scope>runtime</scope>
       </dependency>
       -->
 
       <!-- MySQL driver -->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <scope>runtime</scope>
       </dependency>

现在,你需要通过添加配置文件 src/main/resources/application.properties 来添加连接到数据库的配置。

#数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/my-database
spring.datasource.username=root
spring.datasource.password=admin-password
 
#自动创建表格和数据库
spring.jpa.hibernate.ddl-auto=update

你现在可以启动应用程序并调用现有的端点(endpoints):

#获取所有人
curl http://localhost:8080/people

#添加一个人
curl -i -H "Content-Type:application/json" -d '{"firstName": "Frodo", "lastName": "Baggins"}' http://localhost:8080/people

#再次获取所有人,现在返回创建的人
curl http://localhost:8080/people

你成功地使用了你的初级应用程序,它在你的数据库中写入和读取数据。使用 MySQL Docker 数据库可以让你在几秒钟内建立一个强大的数据库,而且你可以从任何应用程序中使用它。

如何使用数据库容器进行集成测试

该应用程序已经有数据库的相关测试。但是,因为你用一个实际的 MySQL 数据库替换了你的内存数据库,如果你停止你的数据库,测试就不会成功运行。

# 停止数据库
docker rm -f mysql

# 运行测试
./mvnw clean test

... skipped output ...
[ERROR] Tests run: 7, Failures: 0, Errors: 7, Skipped: 0
... skipped output ...

为了快速启动和停止运行测试的容器,有一个方便的工具叫 testcontainers。在那里你可以找到许多编程语言的库,包括 Java。

首先,你需要添加一些依赖项到你的 pom.xml 文件:

       <!-- testcontainer -->
       <dependency>
           <groupId>org.testcontainers</groupId>
           <artifactId>testcontainers</artifactId>
           <version>1.16.3</version>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.testcontainers</groupId>
           <artifactId>mysql</artifactId>
           <version>1.16.3</version>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.testcontainers</groupId>
           <artifactId>junit-jupiter</artifactId>
           <version>1.16.3</version>
           <scope>test</scope>
       </dependency>

你需要更新测试以利用 testcontainers,它在每次测试运行时启动数据库。在测试中添加一个注解和一个字段来利用它:

//添加 imports
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
 
@SpringBootTest
@AutoConfigureMockMvc
@Testcontainers // Annotation to enable testcontainers
public class AccessingDataRestApplicationTests {
 
   //访问已启动数据库的字段
   @Container
   private static MySQLContainer database = new MySQLContainer<>("mysql:5.7.34");
 
   //使用启动的数据库设置数据库配置
   @DynamicPropertySource
   static void databaseProperties(DynamicPropertyRegistry registry) {
       registry.add("spring.datasource.url", database::getJdbcUrl);
       registry.add("spring.datasource.username", database::getUsername);
       registry.add("spring.datasource.password", database::getPassword);
   }

对于每个测试的执行,启动数据库做好准备,这使你在执行测试时可以使用一个实际的数据库。所有的连接、设置、启动和清理都为你完成。

Docker 化你的应用程序

使用简单的 Docker 工具对你的应用程序进行 Docker 化是可能的,但不推荐。

你可以建立你的应用程序,使用一个包含 Java 的基础容器,然后复制并运行你的应用程序。但是有很多陷阱,每种语言和框架都是如此。所以一定要寻找能让你的生活更轻松的工具。

在这个例子中,你将使用 Jibdistroless containers 来轻松构建一个 Docker 容器。将两者结合使用,可以得到一个最小的、安全的、可复制的容器,它在本地和生产中的工作方式是一样的。

要使用 Jib,你需要把它作为一个maven插件添加到你的 pom.xml 文件:

<build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
 
        <!-- Jib plugin -->
           <plugin>
               <groupId>com.google.cloud.tools</groupId>
               <artifactId>jib-maven-plugin</artifactId>
               <version>3.2.1</version>
               <configuration>
                   <from>
                       <image>gcr.io/distroless/java17:nonroot</image>
                   </from>
                   <to>
                       <image>my-docker-image</image>
                   </to>
               </configuration>
           </plugin>
       </plugins>
   </build>

现在你可以建立镜像并运行应用程序:

# 构建 docker 容器
./mvnw compile jib:dockerBuild

# 查找你的构建镜像
docker images

# 启动数据库
docker run --rm -v "$PWD/data":/var/lib/mysql --name mysql -e MYSQL_ROOT_PASSWORD=admin-password -e MYSQL_DATABASE=my-database -p 3306:3306 mysql:8.0.28-debian


# 启动包含你的应用程序的 docker 容器
docker run --net=host my-docker-image

… skipped output…
2022-04-15 17:43:51.509  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-04-15 17:43:51.521  INFO 1 --- [           main] c.e.a.AccessingDataRestApplication       : Started AccessingDataRestApplication in 6.146 seconds (JVM running for 6.568)

该应用程序以网络模式主机 --net=host 启动,这使得它很容易只连接到你启动的数据库。另外,你可以创建一个 docker network,在同一个网络中启动两者。

你可以将你的容器推送到容器 registry,并从任何容器协调工具中使用它,在生产中运行你的应用程序。

总结

在本教程中,你学到了如何利用 Docker 来创建、测试和运行应用程序而不污染你的系统。

一切都在你独立的 Docker 环境中,并在本地工作,像持续集成系统和生产系统中,你可能启动数百个你的应用程序。

你可以在我的 GitHub Docker For Development 应用实例库 中找到可以使用的例子。

我希望你喜欢这篇文章。

如果你喜欢它,觉得有必要给我点赞,或者只是想联系我,在Twitter上关注我

我在 eBay Kleinanzeigen 工作,这是全球最大的电子商务公司之一。顺便说一下,我们正在招聘

参考文献