用 docker-compose 部署服务真是好用,根本停不下来!

4,952 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情

Docker Compose 是个啥?

假设你已经对 Docker 的相关知识已经有所了解,如果不了解可以瞅一眼我的这篇介绍 Docker 的文章:

容器化技术之Docker-从入地到上天

有了 Docker ,为啥还要 Docker Compose 呢?我们来想想,用容器运行一个服务,需要使用 docker run 命令,但如果我要运行多个服务呢?

比如,我有一个 Web 服务,该服务依赖 Redis 服务的存在,因为需要读取 Redis 中的数据,那么我该用一个容器运行,还是用多个容器运行呢?

一个容器运行多个服务会造成 镜像 的复杂度变高, Docker 倾向于一个容器运行一个应用 。那该如何解决一个应用中需要多个容器,并且容器间需要通信这样的问题呢?

答:使用 容器编排Docker Compose 中的 compose 就是 组织、编排 的意思。具体就是可以通过 Docker Compose 对多个容器进行管理。Docker Compose 是一个用于定义和运行多容器 Docker 的应用程序工具。

安装 Docker Compose

Docker Compose 的安装极其简单:

1, 下载 Docker Compose 的可执行程序

下载地址:github.com/docker/comp…

我们把环境放在 Linux 下,所以我们下载这个:

image-20220825161503366.png

下载完了,上传到 Linux 服务器上。或者直接使用如下命令下载:

wget https://github.com/docker/compose/releases/download/v2.10.0/docker-compose-linux-x86_64

2, 将下载下来的 docker-compose-linux-x86_64 文件移动到 /user/bin 目录下并命名为 docker-compose

mv docker-compose-linux-x86_64 /usr/bin/docker-compose

3, 增加 docker-compose 文件的可执行权限

chmod +x /usr/bin/docker-compose

4, 验证

[root@docker ~]# docker-compose version
Docker Compose version v2.10.0

安装完成。

使用 Docker Compose 编排应用程序

Docker Compose 编排容器的步骤

1, 定义应用的 Dockerfile 文件,为了在任何地方都能构建

2, 通过 docker-compose.yml 定义一套服务 services ,这些服务可以在一个隔离的环境中一起运行,并能相互通信

3, docker-compose up 启动一整套服务

就用文章开始说的那个例子,写一个 web 程序,提供接口,该接口返回访问服务的次数,而这个次数需要从 Redis 中读取。

创建 Spring Boot 项目

我们来创建一个 Spring Boot 的 web 程序,访问 http://ip:port/hits 时读取 Redis 中的值,返回这是第几次访问。

@SpringBootApplication
public class DemoAppApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoAppApplication.class, args);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    @RestController
    public class TestController {
        @Autowired
        private StringRedisTemplate redisTemplate;

        @GetMapping("/hits")
        public String test() {
            redisTemplate.opsForValue().increment("hits");
            return "哥们,这是你第 " + redisTemplate.opsForValue().get("hits") + " 次来我的瓜摊了!";
        }
    }
}

pom.xml 依赖咱就不说了,添加 spring-boot-starter-webspring-boot-starter-data-redis

application.properties 配置文件:

# 应用名称
spring.application.name=demo-app
# 应用服务 WEB 访问端口
server.port=8080

spring.redis.host=redis
spring.redis.port=16379
spring.redis.password=123456

这里先不管我的 Redishost 为什么这样配置,而不是配置 IP 地址,下面会说到。

打包后得到 demo-app-0.0.1-SNAPSHOT.jar 文件,并将其上传到 Linux 服务器的 /usr/local/demoapp/app 目录下,注意这个目录有讲究,后面编写 Dockerfile 以及 docker-compose.yml 文件的时候注意目录之间的层级关系。

编写 web 项目的 Dockerfile 文件

Dockerfile 文件的介绍这里就不多说了,请看这里:

juejin.cn/post/690107…

我们直接来编写,在 /usr/local/demoapp/app 目录下,创建 Dockerfile 文件,内容如下:

FROM openjdk:8u222-jre
WORKDIR /usr/local/apphouse
ADD demo-app-0.0.1-SNAPSHOT.jar .
EXPOSE 8080
CMD ["java", "-jar", "demo-app-0.0.1-SNAPSHOT.jar"]

因为咱们是通过运行 jar 包的方式启动项目,所以依赖 Java 运行环境,从 Docker 仓库中找到一个 JDK 8 的镜像:

hub.docker.com/search?q=jd…

image-20220825151615680.png

编写 Redis 服务的 Dockerfile 文件

/usr/local/demoapp/redis 目录下,编写 Dockerfile 文件:

FROM redis:5.0.14
MAINTAINER chendapeng.cn
COPY redis.conf /usr/local/etc/redis/redis.conf
EXPOSE 16379
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]

这里选择的Redis版本是 5.0.14, 其中 redis.conf 是提前从 Redis 的官方 Github 上下载对应版本的 conf 文件,该文件的 Github 地址: github.com/redis/redis…

下载到本地放到 /usr/local/demoapp/redis 目录下,并修改其中几项的内容:

# 这一句注释掉,使其可以被外部访问
# bind 127.0.0.1

# protected-mode 设置为 no
protected-mode no

# 修改端口
port 16379

# 设置密码
requirepass 123456

编写 docker-compose.yml 文件

将 web 容器和 redis 容器组织编排起来,使用 docker-compose.yml 进行定义:

version: '3'
services:
  redis:
    build: ./redis/
    restart: always
  demoapp:
    build: ./app/
    depends_on:
      - redis
    ports:
      - "8080:8080"
    restart: always

这里一定要注意每个服务 build 字段的配置,一定要设置为该服务 Dockerfile 文件所在的文件路径。当前所有文件都准备好了,每个文件的位置如图所示:

image-20220825170438505.png

这里可以解释一下前面的关于 Spring Boot 项目中配置文件:

spring.redis.host=redis
spring.redis.port=16379
spring.redis.password=123456

为什么 Redishost 直接使用 redis 这个字符串而不是 IP 地址了,因为 docker-compose.yml 中定义了名为 redis 的服务,并且 demoapp 项目依赖(depends_on)该服务,那么在容器中就可以直接使用服务名称进行访问 Redis 了。

使用 docker-compose up 启动服务

先来看一下,目前我的环境中什么容器和镜像都没有:

image-20220825171521296.png

进入到 /usr/local/demoapp ,使用命令启动服务:

docker-compose up

第一次启动,需要下载一些镜像:

image-20220825171655317.png

然后就可以看到,首先是 Redis 服务先起来了:

image-20220825171752547.png

然后我们的 web 项目也起来了:

image-20220825171839675.png

现在我们再来看一下容器和镜像情况:

image-20220825171929834.png

验证服务

服务既然已经起来了,我们来运行一下,访问 http://192.168.242.8080/hits

screenshots.gif

牛逼,访问没有问题!

小结

Docker Compose 在单机编排多个容器的时候时是常方便的,比如本文的例子中就一键启动了 RedisSpring Boot 项目,实际上我们还可以加上 MySQLES 等其他服务,这样服务多起来更能显示 Docker Compose 的威力。

另外,Docker Compose 在安装一些软件的时候也是相当的省事的,强烈建议大家学习一波。