乐趣区

关于程序员:从-0-到-1-构建自己的-Docker-应用

本文首发自「慕课网」,想理解更多 IT 干货内容,程序员圈内热闻,欢送关注!

作者 | 慕课网精英讲师 legendtkl

在日常开发或者生产环境中,很多状况下,咱们的零碎都不是一个利用能够搞定的,而是由很多个局部组成,比方 webapp,数据库,缓存等。所以这一章的例子,咱们就以一个 web 利用 + 缓存 redis 作为例子构建一个略微简单点的利用。

应用的语言和利用的版本如下:Python 3.8.1,Flask 库 1.1.1,Redis 库 3.4.1。

  1. web 利用
    这次咱们应用 Python 来编写咱们的 web 利用,上一次咱们应用的是 Go 语言。因为 Go 语言部署间接应用二进制文件,Dockerfile 会极其的简略,为了让大家相熟一下 Dockerfile 的利用,所以这里咱们应用 Python 语言里编写咱们的 web 利用。

Python 语言置信大家都很相熟,不相熟也没有关系,代码都很简略。基于 Python 的 web 网络应用框架比拟闻名的有 Django,Tornado,Flask 等。咱们这里应用 Flask 来构建咱们的利用,因为 Flask 是一种极其轻量的框架,正如作者所说:

Flask is a lightweight WSGI web application framework. It is designed to make getting started quick and easy, with the ability to scale up to complex applications. It began as a simple wrapper around Werkzeug and Jinja and has become one of the most popular Python web application frameworks.

Flask offers suggestions, but doesn’t enforce any dependencies or project layout. It is up to the developer to choose the tools and libraries they want to use. There are many extensions provided by the community that make adding new functionality easy.

对于 Flask 的更多信息,能够参考 Flask 的官方网站或者 Github 主页。

1.1 Flask 装置
Flask 装置很简略,和其余 Python 依赖装置根本没有区别。

pip install flask
1.2 Flask demo
咱们后面说了 Flask 是一个十分轻量的 web 框架,那么有多轻量呢?轻量到咱们应用上面几行代码就能够构建进去一个简略的 web 利用。

from flask import Flask

app = Flask(__name__)

@app.route(‘/’)
def hello():

return 'Hello, Flask'

启动利用。

$ env FLASK_APP=hello.py flask run

  • Serving Flask app “hello”
  • Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

利用默认启动在 5000 端口,咱们能够通过 -p 参数指定援用的启动端口。当然 Flask 还反对其余参数,咱们能够通过 flask run –help 进行查看。

root@a36d1df88169:/# flask run –help
Usage: flask run [OPTIONS]

Run a local development server.

This server is for development purposes only. It does not provide the
stability, security, or performance of production WSGI servers.

The reloader and debugger are enabled by default if FLASK_ENV=development
or FLASK_DEBUG=1.

Options:
-h, –host TEXT The interface to bind to.
-p, –port INTEGER The port to bind to.
–cert PATH Specify a certificate file to use HTTPS.
–key FILE The key file to use when specifying a

                              certificate.

–reload / –no-reload Enable or disable the reloader. By default

                              the reloader is active if debug is enabled.

–debugger / –no-debugger Enable or disable the debugger. By default

                              the debugger is active if debug is enabled.

–eager-loading / –lazy-loader

                              Enable or disable eager loading. By default
                              eager loading is enabled if the reloader is
                              disabled.

–with-threads / –without-threads

                              Enable or disable multithreading.

–extra-files PATH Extra files that trigger a reload on change.

                              Multiple paths are separated by ':'.

–help Show this message and exit.
利用启动了之后,咱们能够拜访 5000 端口来验证利用是不是失常的。

[root@docker ~]# curl localhost:5000
Hello, Flask
1.3 Flask 应用
下面介绍了 Flask 最简略的应用 demo,上面咱们应用 Flask 来编写咱们利用和 Redis 进行交互。首先咱们也要先装置 Python 依赖库:redis。

pip install redis
咱们次要要实现三个性能:

redis 连贯
提供一个 route set 实现对 redis 中的值进行设置
提供一个 route get 实现对 redis 中的值进行查问
redis 连贯
redis 连贯,咱们间接应用 Python 的依赖库 Redis。

import redis

redis_client = redis.Redis(host=redis_host, port=redis_port, db=0)
其中连贯 Redis 须要应用三个参数:

host: redis 的 host
port: redis 的端口
db:redis 中的数据库,咱们应用 db = 0 即可。
这里的一个外围问题是 redis 运行在另外一个 Docker 中,那咱们在利用的 Docker 中如何连贯 redis 实例呢?也就是如何发现 redis 的 host 和 port 呢?

在 Docker 技术中咱们能够在启动 Docker 的时候指定参数 –link 将两个 Docker 的网络进行买通。在上面部署的时候咱们再细说。

set route
编写一个 route,能够对 redis 进行写入。

@app.route(‘/set’)
def set():

key = request.args.get("key")
value = request.args.get("value")
redis_client.set(key, value)
return 'OK. We have set' + key + 'to be' + value

其中 request.args 中能够获取到 url 中的参数。然而下面的代码没有做参数校验,key 和 value 可能是空,咱们加一个参数校验的逻辑。

@app.route(‘/set’)
def set():

key = request.args.get("key")
value = request.args.get("value")
if key is None or value is None:
    return 'OOps, the key or value is NULL'
redis_client.set(key, value)
return 'OK. We have set' + key + 'to be' + value

get route
编写一个 route 对 redis 中的值查问

@app.route(‘/get’)
def get():

key = request.args.get('key')
if key is None:
    return 'OOps, the key is null'
value = redis_client.get(key)
return value

至此,咱们的 web 利用代码编写实现,残缺的代码如下,其中 redis-host 当初还是一个占位符,咱们部署的时候会把这个变量注入进来。

from flask import Flask, request
import redis

redis_client = redis.Redis(host=’redis-host’, port=6379, db=0)
app = Flask(__name__)

@app.route(‘/set’)
def set():

key = request.args.get('key')
value = request.args.get('value')
if key is None or value is None:
    return 'OOps, the key or value is NULL'
redis_client.set(key, value)
return 'OK. We have set' + key + 'to be' + value

@app.route(‘/get’)
def get():

key = request.args.get('key')
if key is None:
    return 'OOps, the key is null'
value = redis_client.get(key)
return value
  1. Dockerfile
    上面开始编写咱们的 Dockerfile。回顾一下咱们下面编写 web 利用过程中,次要装置了依赖 flask 和 redis 依赖。咱们能够很简略写进去咱们的 Dockerfile 如下,并命名为 Dockerfile。

from python:3

RUN pip install flask
RUN pip install redis
RUN mkdir /data

COPY hello.py /data/
WORKDIR /data

EXPOSE 5000
ENV FLASK_APP=/data/hello.py
ENTRYPOINT [“flask”, “run”, “-h”, “0.0.0.0”]
咱们对这个 Dockerfile 进行一个简略解释:

from:示意根底镜像是 python:3;
RUN:示意在 docker build 的时候会执行前面的几个命令;
COPY:拷贝文件或者目录都能够;
WORKDIR:示意启动容器之后,以后的工作目录;
EXPOSE:示意容器要裸露 5000 端口;
ENV:环境变量;
ENTRYPOINT:示意 Docker 容器的启动过程。这里 entrypoint 中的 flask run 咱们减少了参数 -h 0.0.0.0。如果不加这个参数的话,过程默认绑定到 127.0.0.1,里面是没有方法拜访的。
通过该 dockerfile 来构建镜像。根本每一个命令都会对应一个 step,如下。

[root@docker web]# docker build -t web:v1 .
Sending build context to Docker daemon 3.584kB
Step 1/8 : from python:3
—> efdecc2e377a
Step 2/8 : RUN pip install flask
—> Running in c4dfe7b3e466
Collecting flask
Downloading Flask-1.1.1-py2.py3-none-any.whl (94 kB)
Collecting itsdangerous>=0.24
Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)
Collecting Jinja2>=2.10.1
Downloading Jinja2-2.11.1-py2.py3-none-any.whl (126 kB)
Collecting Werkzeug>=0.15
Downloading Werkzeug-1.0.0-py2.py3-none-any.whl (298 kB)
…….
Step 8/8 : ENTRYPOINT [“flask”, “run”]
—> Running in 25594e1de72f
Removing intermediate container 25594e1de72f
—> d18b55e4d1fd
Successfully built d18b55e4d1fd
Successfully tagged web:v1
构建胜利之后,咱们能够通过 docker images 查看到咱们方才 build 进去的镜像 web。

[root@docker demo]# docker images | grep web
web v1 02cc264143dc 6 minutes ago 943MB

  1. 部署
    咱们先来部署一个 Redis Docker,-d 参数示意以 daemon 的形式运行。-p 示意端口映射。-name 示意 Docker 容器的名字叫 redis-test。

docker run –name redis-test -p 6379:6379 -d redis:latest
上面部署咱们的 web 利用。

[root@docker ~]# docker run -p 5000:5000 –link redis-test:redis-host -d –name web web:v1
64eef1f67c3934b6257510f47b587c59cee635188a4043b749966e71d2bc8c08
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64eef1f67c39 web:v1 “flask run -h 0.0.0.0” 2 seconds ago Up 1 second 0.0.0.0:5000->5000/tcp web
其中有一个运行参数须要进行简略阐明,也就是 –link。link 前面跟一对映射的值,左侧的为曾经存在的 Docker 容器,右侧的为该容器映射到咱们启动的 Docker 利用中的 host 名字,这里也就是 web 这个 Docker 容器。咱们上面通过 docker exec 进入到容器中看一下 link 是怎么做的。

[root@docker ~]# docker exec -ti 64eef1f67c39 /bin/bash
root@64eef1f67c39:/data#
咱们查看一下 hosts 文件。

root@64eef1f67c39:/data# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.5 redis-host 0d748e8ce766 redis-test
172.17.0.6 64eef1f67c39
咱们能够看到 redis-host 曾经被写到 hosts 中,所以咱们在 web 这个 Docker 容器中就能够通过 redis-host 这个主机名拜访到 Redis 容器了,这也是咱们的利用代码的写法。

  1. 验证
    部署实现,咱们上面进行一个简略的验证。在宿主机上执行上面命令去设置一对 kv: <imooc, imooc.com> 写入到 Redis 中。

[root@docker ~]# curl “localhost:5000/set?key=imooc&value=imooc.com”
OK. We have set imooc to be imooc.com
第二个申请去读取该值,如下。

[root@docker ~]# curl “localhost:5000/get?key=imooc”
imooc.com

  1. 总结
    至此,咱们第一个入手实际的 Docker 利用曾经实现。原本想弄一个更简单的利用,然而限于篇幅,只能做了一下取舍。尽管简略,还是倡议各位同学进行入手实际。毕竟纸上得来终觉浅,绝知此事要躬行。

欢送关注「慕课网」,发现更多 IT 圈优质内容,分享干货常识,帮忙你成为更好的程序员!

退出移动版