构建镜像及容器编排

构建镜像及容器编排

本篇文章参考了示例

2018-04-04 更新:

改用基于 alpine 的镜像,在容量上较默认镜像更小。

使用 Dockerfile 创建镜像

编写 WEB 应用

之前,我们直接用官方的 MySQL 镜像创建了一个 MySQL 实例,但若想把自己的应用通过 Docker 部署,那还是需要通过 Dockerfile 构建自己的镜像。

首先,我们利用 python 的 flask 框架建立一个 hello world 的 web 应用。

# app.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello():
    return 'Hello, World!'

if __name__ == '__main__':
    # 默认端口为5000
    app.run(host='0.0.0.0', debug=True)

在当前目录下,运行python app.py即可启动应用。

启动Flask

然后,我们在浏览器中输入http://localhost:5000就能看到熟悉的 hello world。

helloworld

编写 Dockfile

在当前目录下,我们先建立一个Dockerfile文件,然后键入以下内容。

# 基于alpine的python3.6镜像开始构建
FROM python:alpine3.6
# 切换工作目录至/code(可以理解为cd ./code)
WORKDIR /code
# 将代码文件添加到镜像的/code目录下
ADD ./app.py .
# 安装flask库
# 这里使用了清华的镜像源,为了安装的快一些
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flask
# 运行
CMD [ "python", "app.py" ]

随后,启动一个 PowerShell 窗口,并切换到当前目录下。

# 构建镜像
# -t 表示将该镜像命名为demo,并打上flask的标签
docker build -t demo:flask .

这边需要注意的是最后还有一个.,代表在当前目录下查找Dockerfile

在成功构建之后,我们来启动这个镜像的一个实例。

# 启动容器
# --name 参数将该容器命名为demo.flask,方便后续操作
# -d 参加将容器切入后台运行,网上的教程也称为守护进程
# -p 参数将容器内的5000端口,映射到本地的5000端口,使得我们能在本地访问
docker run --name demo.flask -d -p 5000:5000 demo:flask

至此,一个使用 Docker 部署的 WEB 应用就完成了,我们可以通过浏览器访问http://localhost:5000看到和之前一样的 Hello World 界面。

Docker 镜像中有什么?

其实,我也不是特别清楚 Docker 镜像中到底包含了什么。但我们还是看到在基于 python 3.6 的镜像上,我们添加了什么。

通过docker exec -it demo.flask bash,我们进入容器内部,键入ls查看当前目录下的文件。

镜像文件信息

我们可以看到的是,进入后的默认目录就是我们在Dockerfile中设置的/code,同时,里面有我们添加的 app.py 文件。

另外,如果有兴趣,还可以再看一下pip list里面除了最基础的 pip 和 wheel,其余的就是我们在Dockerfile中使用 pip 安装的库。

使用 docker-compose 编排容器

很多时候,我们的应用往往不能完全塞入同一个容器中,比如需要连接数据库的情况,这时候就需要多个容器之间的协调。Docker 对此也有一个利器,docker-compose。在默认情况下,docker-compose 会随 docker 一同安装好。这里,我根据网上的教程,简单的说下 docker-compose 的使用。

编写一个基于 redis 的 web 应用

redis 是一个内存数据库,可以用来作为应用缓存,这里我们通过 redis 和 flask 实现一个统计访问次数的应用。

首先,修改之前的 WEB 应用,加入 redis 支持。

from flask import Flask
from redis import Redis

app = Flask(__name__)
# 注意,此处的host需和docker-compose中redis的service名相同
redis = Redis(host='redis', port=6379)


@app.route('/')
def hello():
    count = redis.incr('hits')
    return 'Hello World! 此页面已被访问%d次。\n' % count

if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True)

Dockerfile中,使用 pip 安装 redis 库。

FROM python:alpine3.6
WORKDIR /code
ADD ./app.py .
# 修改这里,添加redis库
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flask redis
CMD [ "python", "app.py" ]

自此,一个具有访问次数统计的 WEB 应用就完成了。。。?

显然,还缺少一步。

编写 docker-compose.yml

既然提到了 docker-compose,那总是要用的。在同一目录下,我们建立一个docker-compose.yml,键入以下内容。

# 由于一些未知的编码原因,若要复制此段配置文件,请手动去掉注释
# 声明使用version 3的docker-compose.yml格式
# 详情可以参考:https://docs.docker.com/compose/compose-file/
version: "3"
# 定义有关服务
services:
  # 使用官方的alpine版redis镜像创建redis实例
  # 注意这里的redis,指的是服务名,需和之前host中的对应
  # 至于原因,之后再解释
  redis:
    image: "redis:alpine"

  # 我们的WEB应用,这里构建为demo:flask-redis镜像
  web:
    image: "demo:flask-redis"
    build: .
    # 添加对redis服务的依赖
    depends_on:
      - redis
    # 映射5000端口
    ports:
      - "5000:5000"

保存后,我们在当前目录下打开 PowerShell 窗口,执行docker-compose build来完成构建。

然后,使用docker-compose up -d来启动应用。

访问http://localhost:5000可以看到如下界面。

累计访问界面

使用docker ps,我们也可以看到两个被启动的容器。

容器编排

至此,应该算是完成了吧。。。

另外,补充一条,如果不再需要这两个容器,可以使用docker-compose down -v来删除。注意~记得加-v 参数,因为 redis 容器会创建一个数据卷,如果多次使用不删除的话。。emmm。。硬盘大就当我没说。

支付宝收款码
Copyright © yiluomyt 2020