如何把Python应用构建为Docker容器

现在云原生越来越流行, 容器化势在必行, 作为一个开发人员, 多多少少也要接触一些容器相关的操作, 其中最基础的操作是如何把自己的应用构建为一个 Docker 容器, 并管理。本文以 starlette 框架和后台的开发常见3件套 Nginx , MySQL 和 Redis 为底创建一个简单的Web后台演示项目, 并一步一步介绍如何编写成一个容器以及容器的运行。

1.创建项目

第一步会先创建一个 Python 后台项目, 这个项目包含3个接口, 一个接口用来测试服务是否正常, 另外一个是测试 MySQL 调用, 最后一个是测试 Redis 调用。

首先是创建一个后台项目以及依赖:

➜  example_python git:(master) mkdir python_on_docker          
➜  example_python git:(master) cd python_on_docker 
# 一个项目配套一个虚拟环境, 如果熟悉, 建议用porety来处理项目的python和venv配套环境问题, 这里为了演示方便, 使用了venv
➜  python_on_docker git:(master) python3.7 -m venv venv
➜  python_on_docker git:(master) source venv/bin/activate 
➜  python_on_docker git:(master) touch __init__.py  # 每个Python项目要确保有一个__init__.py文件 

# 可以看到多了个venv的环境, 目前已经切到venv, 开始安装依赖
(venv) ➜  python_on_docker git:(master) pip install starlette aiomysql aioredis uvicorn
(venv) ➜  python_on_docker git:(master) pip install cryptography  # aiomysql需要该模块提供加密算法
# 生成pip安装的依赖文件
(venv) ➜  python_on_docker git:(master) python -m pip freeze > requirements.txt

之后创建项目主文件 example.py , 该文件主要提供API服务,里面包含上面所说的3个接口, 示例代码如下(源码):

from typing import Optional, Tuple

import aiomysql
import aioredis
from starlette.applications import Starlette
from starlette.config import Config
from starlette.requests import Request
from starlette.responses import JSONResponse, PlainTextResponse
from starlette.routing import Route


config: Config = Config(".env")
mysql_pool: Optional[aiomysql.Pool] = None
redis: Optional[aioredis.Redis] = None


async def on_start_up():
    """连接MySQL和Redis"""
    global mysql_pool
    global redis

    mysql_pool = await aiomysql.create_pool(
        host=config("MYSQL_HOST"),
        port=config("MYSQL_PORT", cast=int),
        user=config("MYSQL_USER"),
        password=config("MYSQL_PW"),
        db=config("MYSQL_DB"),
    )
    redis = aioredis.Redis(
        await aioredis.create_redis_pool(
            config("REDIS_URL"),
            minsize=config("REDIS_POOL_MINSIZE", cast=int),
            maxsize=config("REDIS_POOL_MAXSIZE", cast=int),
            encoding=config("REDIS_ENCODING")
        )
    )


async def on_shutdown():
    """关闭MySQL和Redis连接"""
    await mysql_pool.wait_closed()
    await redis.wait_closed()


def hello_word(request: Request) -> PlainTextResponse:
    """测试接口调用接口"""
    return PlainTextResponse("Hello Word!")


async def mysql_demo(request: Request) -> JSONResponse:
    """测试MySQL调用接口"""
    count: int = int(request.query_params.get("count", "0"))
    async with mysql_pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute("SELECT %s;", (count, ))
            mysql_result_tuple: Tuple[int] = await cur.fetchone()
    return JSONResponse({"result": mysql_result_tuple})


async def redis_demo(request: Request) -> JSONResponse:
    """测试Redis调用接口"""
    count: int = int(request.query_params.get("count", "0"))
    key: str = request.query_params.get("key")
    if not key:
        return JSONResponse("key is empty")
    result: int = await redis.incrby(key, count)
    await redis.expire(key, 60)
    return JSONResponse({"count": result})


app: Starlette = Starlette(
    routes=[
        Route('/', hello_word),
        Route('/mysql', mysql_demo),
        Route('/redis', redis_demo)
    ],
    on_startup=[on_start_up],
    on_shutdown=[on_shutdown]
)

项目文件创建完毕, 接着再创建一个配套的配置文件 .env ( starlette 的config会自动加载 .env 的配置):

# 按自己的配置信息更改配置
MYSQL_DB="mysql"
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PW=""

REDIS_URL="redis://localhost"
REDIS_POOL_MINSIZE=1
REDIS_POOL_MAXSIZE=10
REDIS_ENCODING="utf-8"

到现在为止, 目录里只有 example.py 主文件, .env 配置文件以及 requirements.txt 的依赖文件, 现在开始启动应用查看应用是否能正常启动(注意修改mysql和redis的配置文件, 目前假设已经在本地安装好mysql和redis):

# 使用python -m uvicorn可以防止调用到外部的uvicorn
python -m uvicorn example:app
# 以下为终端输出
INFO:     Started server process [4616]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

通过终端的输出可以看到我们的服务已经启动并监听本机的8000端口,接下来测试接口可否正常使用:

➜  curl http://127.0.0.1:8000
Hello Word!
➜  curl http://127.0.0.1:8000/mysql
{"result":[0]}
➜  curl http://127.0.0.1:8000/mysql\?count\=10
{"result":[10]}
➜  curl http://127.0.0.1:8000/mysql\?count\=50
{"result":[50]}
➜  curl http://127.0.0.1:8000/redis\?key\=test
{"count":0}
➜  curl http://127.0.0.1:8000/redis\?key\=test\&count\=2
{"count":2}
➜  curl http://127.0.0.1:8000/redis\?key\=test\&count\=2
{"count":4}
➜  curl http://127.0.0.1:8000/redis\?key\=test\&count\=2
{"count":6}
➜  curl http://127.0.0.1:8000/redis\?key\=test\&count\=2
{"count":8}    

通过输出可以发现, 我们的测试结果正常, 接口可以正常使用,前菜到此结束, 接下来是开始利用 Docker 部署Python Web应用之旅.

2.为项目创建镜像并运行

目前我们还没碰过 Docker , 从这里开始, 就开始使用 Docker 了, 但在使用之前要确保自己安装了 Docker , 每个平台都有不同的安装方法且资料很多, 官方资料也很详细, 这里就不多做描述了。

在 Docker 中创建镜像很简单, 只需要通过一个 Dockerfile 文件来告诉 Docker 如何制作镜像即可, Dockerfile 主要包括两个用途, 一个是对当前镜像的描述;一个是指导 Docker 完成应用的容器化(创建一个包含当前应用的镜像), Dockerfile 能实现开发和部署两个过程的无缝切换, 同时 Dockerfile 还能帮助新手快速熟悉这个项目( Dockerfile 对当前的应用及其依赖有一个清晰准确的描述,并且非常容易阅读和理解&

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值