15-多容器复杂应用的部署

15-多容器复杂应用的部署

此节主要是通过部署一个复杂的应用场景,进而练习容器的网络相关知识。

创建一个flask-web应用

  1. 创建一个 flask-web 文件夹

    mkdir flask-web
    

    在此文件夹内创建 app.py 文件

    cd flask-web
    touch app.py
    
  2. 编写一个简单的 web 程序

    import os
    import socket
    import redis
    from flask import Flask
    
    app = Flask(__name__)
    redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
    
    
    @app.route('/')
    def hello():
    	redis.incr('hits')
    	return 'hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'), socket.gethostname())
    
    if __name__ == '__main__':
    	app.run(host="0.0.0.0", port=5000, debug=True)
    

创建一个 redis 数据库容器

  1. 创建容器

    docker run -d --name redis redis
    

    这里为什么没有增加端口呢,是因为我们想内部自己访问,不想暴露给外面,这样也比较安全。

  2. 查看运行情况

    [vagrant@10 flask-web]$ docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
    d9916db96279        redis               "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        6379/tcp             redis
    

部署

  1. 创建自定义的 web 程序镜像

    首先编写Dockerfile

    FROM python:2.7
    LABEL maintaner="vincent <[email protected]>"
    COPY ./app.py /app/
    WORKDIR /app
    RUN pip install flask redis
    EXPOSE 5000
    CMD ["python", "app.py"]
    

    构建镜像

    docker build -t vincent/flask-redis .
    
  2. 创建 flask-redis 的容器

    docker run -d --link redis --name flask-redis -e REDIS_HOST=redis vincent/flask-redis
    

    -d 是后台执行
    –link 是连接redis容器,使 flask-redis 容器可以访问 redis 容器
    -e 设定容器的环境变量,下面讲

  3. 问题解决

    上一步构建完成后,查看容器运行情况

    docker ps
    

    发现刚刚创建的flask-redis容器并没有运行,而是停止了,说明工作不正常,那么我怎么办?

    首先我们查看运行日志

    [vagrant@10 flask-web]$ docker logs flask-redis 
    Traceback (most recent call last):
      File "app.py", line 7, in <module>
        redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
    NameError: name 'Redis' is not defined
    

    发现这里有一个错误,这是使用redis错误导致的,app.py 修改如下

    import os
    import socket
    import redis
    from flask import Flask
    
    app = Flask(__name__)
    redis = redis.Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
    
    
    @app.route('/')
    def hello():
    	redis.incr('hits')
    	return 'hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'), socket.gethostname())
    
    if __name__ == '__main__':
    	app.run(host="0.0.0.0", port=5000, debug=True)
    

    重新构建镜像

    docker rm flask-redis && docker rmi vincent/flask-redis
    

    重新创建容器

    docker run -d --link redis --name flask-redis -e REDIS_HOST=redis vincent/flask-redis
    
  4. 进入 flask-redis 容器

    docker exec -it flask-redis /bin/bash
    

    查看 env

    root@99a298edd5da:/app# env
    

    我们能在返回的内容中找到这样一条环境变量

    REDIS_HOST=redis
    

    说明刚刚创建容器的时候参数 -e的作用就在此。

  5. 测试网络

    测试ping redis 查看是否连通

    root@99a298edd5da:/app# ping redis
    PING redis (172.17.0.4) 56(84) bytes of data.
    64 bytes from redis (172.17.0.4): icmp_seq=1 ttl=64 time=0.079 ms
    64 bytes from redis (172.17.0.4): icmp_seq=2 ttl=64 time=0.068 ms
    

    ping redis 是通的。这是因为

    redis = redis.Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
    

    在这里的 REDIS_HOST 被替换成了我们设定的名字,其实这段代码在访问的时候其实是直接访问的 redis,因为设定了 --link 参数,那么是可以访问的,而不需要ip。到这里有的人会有疑问,为什么不直接在代码中写 redis 呢?原因是方便我们后续更改名称,我们只需要在创建容器的时候指定名称即可,你可以叫 redis1,redis2 都可以。

    我们在这个容器内访问 web 服务

    root@99a298edd5da:/app# curl 127.0.0.1:5000
    hello Container World! I have been seen 1 times and my hostname is 99a298edd5da.
    

    这个web程序运行是正常的。

  6. 设定端口

    退出容器,测试访问本地 5000 端口

    [vagrant@10 flask-web]$ curl 127.0.0.1:5000
    curl: (7) Failed connect to 127.0.0.1:5000; 拒绝连接
    

    我们无法访问,这是因为我们只是暴露了 容器的 5000端口,但是并没有和本地端口进行绑定。

    那我们重新创建容器

    docker stop flask-redis && docker rm flask-redis
    docker run -d -p 5000:5000 --link redis --name flask-redis -e REDIS_HOST=redis vincent/flask-redis
    

    再次测试访问本地 5000 端口

    [vagrant@10 flask-web]$ curl 127.0.0.1:5000
    hello Container World! I have been seen 2 times and my hostname is e2ecfc2256f7.
    

总结

我们通过这个例子我们创建了两个容器,并且相互之间有访问设定,这很符合我们前后端开发的一个模式,一般 web程序 和 数据是分离的,这也是我们把 redis 单独封装在一个容器的原因。

这里我们在创建容器的时候使用了 -e 参数,我们详细介绍一下。

创建一个带-e参数的test4 容器

docker run -d -e PENG=vincent --name test4 busybox /bin/sh -c "while true; do sleep 3600; done"

进入容器

docker exec -it test4 /bin/sh

这里说明一下何时加 -it 参数当我们使用 exec 的时候需要加,这时我们想进入一个容器,如果我们在创建一个容器的时候,也就是run命令,那么是否加-it取决于,这个容器内的启动命令配置,例如: 如果使用 ENTRYPOINT [“ls”] 那么我们不需要加 -it,如果什么都没有设置,那么就需要加,一般这样使用docker run -it test1 /bin/sh ls

执行 env

/ # env
HOSTNAME=51801dc17c67
SHLVL=1
HOME=/root
TERM=xterm
PENG=vincent
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/

我们可以看到 PENG=vincent 已经被设置在容器内了。这有什么用呢,有的时候有些程序需要读取环境变量才能工作,这就很有用了。

最后我们再回顾一下这节部署的程序网络模型图

在这里插入图片描述

我们部署的两个容器是在同一台linux主机内的,他们可以访问是很简单的,那么如果是两台linux呢?

在这里插入图片描述

我们假设这两台linux主机是可以通信的,现在我们想把 redis 部署在一台linux主机上,flask-web 部署在另一台linux主机上,他们如何通信?如何配置? 大家思考一下。

答案将在下一节我们讲解。

发布了145 篇原创文章 · 获赞 357 · 访问量 44万+

猜你喜欢

转载自blog.csdn.net/wf19930209/article/details/87381307
今日推荐