使用第三方“容器化”服务
Microblog 的容器版本看起来不错,但我还没有真正考虑过很多关于存储的问题。 实际上,由于我没有设置 DATABASE_URL
环境变量,因此应用程序正在使用默认 SQLite 数据库并将数据存储在容器内部的文件系统上。 当你停止并删除容器时,你认为数据去哪里了? 数据也会被删除!
容器中的文件系统是 临时的 ,这意味着它随着容器的删除而删除。 你可以将数据写入容器内的文件系统,并且容器可以正常读写数据,但如果出于任何原因需要回收容器并将其替换为新的容器,则应用程序保存到容器内的任何数据将永远丢失。
容器应用程序的一个好的设计策略是保持应用程序容器 无状态 。 如果你的应用程序代码和数据容器没有任何问题,可以将其丢弃并替换为新的容器,容器变为真正的一次性容器,这在简化升级部署方面非常有用。
但是,这意味着数据必须放在应用程序容器之外的某个位置。 这就是神奇的 Docker 生态系统发挥作用的地方了。 Docker 容器镜像仓库包含大量的容器镜像。你已经了解了 Python 容器镜像,我正在使用它作为我的 Microblog 容器的基础镜像。 除此之外,Docker 还为 Docker 容器镜像仓库中的许多其他语言,数据库和其他服务维护镜像,如果这还不够,Docker 容器镜像仓库还允许公司为其产品发布容器镜像,并且像你我这样的常规用户也可以发布自己的镜像。 这意味着安装第三方服务需要做出的努力会减少成只需在 Docker 容器镜像仓库中找到合适的镜像,并通过带有适当参数的 docker run
命令启动它。
所以我现在要做的是创建两个额外的容器,一个用于 MySQL 数据库,另一个用于 Elasticsearch 服务,然后我将加长启动 Microblog 容器的命令, 以使其能够访问这两个新的容器。
添加 MySQL 容器
像许多其他产品和服务一样,MySQL 在 Docker 镜像仓库中提供了公共容器镜像。 就像我自己的 Microblog 容器一样,MySQL 依赖于需要传递给 docker run
的环境变量。 他们配置了密码,数据库名称等。在镜像仓库中有许多 MySQL 镜像时,我决定使用由 MySQL 官方团队维护的镜像。 你可以在其镜像仓库页面找到有关 MySQL 容器镜像的详细信息: https://hub.docker.com/r/mysql/mysql-server/ 。
回顾一下在 第十七章 中设置 MySQL 的繁琐过程,你就会赞叹在 Docker 中部署 MySQL 的轻松体验。 这里是启动 MySQL 服务器的 docker run
命令:
$ docker run --name mysql -d -e MYSQL_RANDOM_ROOT_PASSWORD=yes \
-e MYSQL_DATABASE=microblog -e MYSQL_USER=microblog \
-e MYSQL_PASSWORD=<database-password> \
mysql/mysql-server:5.7
这就对了! 在安装了 Docker 的任何机器上,你可以运行上面的命令,就会得到一个完成安装的 MySQL 服务器,它具有一个随机生成的 root 密码,一个名为 microblog
的全新数据库和一个名字相同的用户,该用户具备访问这个数据库的所有权限。 请注意,你需要输入正确的密码,以便它可以从 MYSQL_PASSWORD
环境变量获得。
现在在应用程序方面,我需要添加一个 MySQL 客户端软件包,就像我在 Ubuntu 上进行传统部署一样。 我将再次使用 pymysql
,我可以将它添加到 Dockerfile 中:
Dockerfile :添加 pymysql 到 Dockerfile 中。
# ...
RUN venv/bin/pip install gunicorn pymysql
# ...
任何时候对应用程序或 Dockerfile 进行更改后,都需要重建容器镜像:
$ docker build -t microblog:latest .
现在我可以再次启动 Microblog,但是这次连接到数据库容器,以便两者都可以通过网络进行通信:
$ docker run --name microblog -d -p 8000:5000 --rm -e SECRET_KEY=my-secret-key \
-e MAIL_SERVER=smtp.googlemail.com -e MAIL_PORT=587 -e MAIL_USE_TLS=true \
-e MAIL_USERNAME=<your-gmail-username> -e MAIL_PASSWORD=<your-gmail-password> \
--link mysql:dbserver \
-e DATABASE_URL=mysql+pymysql://microblog:<database-password>@dbserver/microblog \
microblog:latest
--link
选项告诉 Docker 让正要运行的容器可以访问参数中指定的容器。 该参数包含由冒号分隔的两个名称。 第一部分是要链接的容器的名称或 ID,在本例中是我在上面创建的一个名为 mysql
的容器。 第二部分定义了一个可以在这个容器中用来引用链接的主机名。 这里我使用 dbserver
作为代表数据库服务器的通用名称。
通过建立两个容器之间的链接,我可以设置 DATABASE_URL
环境变量,以便 SQLAlchemy 被引导使用其他容器中的 MySQL 数据库。 数据库 URL 将使用 dbserver
作为数据库主机名, microblog
作为数据库名称和用户,以及你在启动 MySQL 时选择的密码。
我在试用 MySQL 容器时注意到的一件事是,这个容器需要几秒钟才能完全运行并准备好接受数据库连接。 如果启动 MySQL 容器,然后立刻启动应用容器,在 boot.sh 脚本尝试运行 flask db migrate
时,则可能会因数据库未准备好接受连接而失败。 为了使我的解决方案更加健壮,我决定在 boot.sh 中添加一个重试循环:
boot.sh :重试数据库连接。
#!/bin/sh
source venv/bin/activate
while true; do
flask db upgrade
if [[ "$?" == "0" ]]; then
break
fi
echo Upgrade command failed, retrying in 5 secs...
sleep 5
done
flask translate compile
exec gunicorn -b :5000 --access-logfile - --error-logfile - microblog:app
此循环检查 flask db upgrade
命令的退出代码,如果它不为零,则认为出现了问题,因此它会等待 5 秒钟然后重试。
添加 Elasticsearch 容器
Elasticsearch Docker 文档 演示了如何将该服务作为单一节点以用于开发模式,以及部署两个节点的生产环境服务。 现在,我将使用单节点模式,并使用引擎开源的“oss”镜像。 容器使用以下命令启动:
$ docker run --name elasticsearch -d -p 9200:9200 -p 9300:9300 --rm \
-e "discovery.type=single-node" \
docker.elastic.co/elasticsearch/elasticsearch-oss:6.1.1
这个 docker run
命令与我用于 Microblog 和 MySQL 的命令有很多相似之处,但是有一些有趣的区别。 首先,有两个 -p
选项,这意味着这个容器将在两个端口上而不是一个端口上进行监听。 端口 9200 和 9300 都映射到主机中的相同端口。
另一个区别在于用于引用容器镜像的语法。 对于我在本地构建的镜像,语法是 <name>:<tag>
。 MySQL 容器使用格式为稍微更完整的 <account>/<name>:<tag>
语法,适用于在 Docker 镜像仓库中引用容器镜像。 我使用的 Elasticsearch 镜像遵循模式 <registry>/<account><name>:<tag>
,其中包括镜像仓库的地址作为第一个组件。 此语法用于未托管在 Docker 镜像仓库中的镜像。 在本处,Elasticsearch 在 docker.elastic.co 上运行自己的容器镜像仓库服务,而不是使用由 Docker 维护的主镜像仓库。
所以,现在我已经启动并运行了 Elasticsearch 服务,我可以修改 Microblog 容器的启动命令以创建指向它的链接并设置 Elasticsearch 服务 URL:
$ docker run --name microblog -d -p 8000:5000 --rm -e SECRET_KEY=my-secret-key \
-e MAIL_SERVER=smtp.googlemail.com -e MAIL_PORT=587 -e MAIL_USE_TLS=true \
-e MAIL_USERNAME=<your-gmail-username> -e MAIL_PASSWORD=<your-gmail-password> \
--link mysql:dbserver \
-e DATABASE_URL=mysql+pymysql://microblog:<database-password>@dbserver/microblog \
--link elasticsearch:elasticsearch \
-e ELASTICSEARCH_URL=http://elasticsearch:9200 \
microblog:latest
在运行此命令之前,如果你仍然在运行 Microblog 容器,请先停止它。 还要仔细操作来为数据库设置正确的密码,并让 Elasticsearch 服务的参数处于命令中的恰当位置。
现在你应该可以访问 http://localhost:8000 并使用搜索功能。 如果你遇到任何错误,可以通过查看容器日志来对其进行排查。 你很可能希望查看 Microblog 容器的日志,其中将显示任何 Python 堆栈跟踪:
$ docker logs microblog
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论