使用Docker Compose,Django和Create React App创建应用程序
如果你想跳过文本,或者迷失一些引用,可以在GitHub上找到本教程的最终代码。
受到Squiggle和Matter of Stats等体育数据网站的启发,在构建Tipresias(我的小型机器学习模型)的应用程序时,我想要包含一个适当的前端,包括指标,K线走势图和逐个圆形提示。我已经知道我必须对这个东西进行dockerize,因为我正在处理跨越Python和R的多个包,并且这种复杂的依赖关系在远程服务器环境中难以管理(并且不可能在以外的地方运行)没有使用Docker的像Heroku这样的盒子服务。我可以避免通过使用基本的Django视图(即静态HTML模板)来构建我的页面来加剧我的复杂性问题,但是曾经使用过的React组件嫁接的古老Rails视图的混搭,以增加一点交互性(然后很多交互性),我更喜欢从我的前端和后端之间的明确分离开始。更重要的是,我想专注于机器学习,数据工程和服务器端逻辑(更不用说我无法用湿纸袋设计出来的事实),所以我聪明可爱的妻子同意了帮我解决这个问题,在10年前的范例中,她无法满足于编码。它将成为一个现代的网络应用程序架构,或者我将不得不填补我自己的div。
组合Docker,Django和React的问题在于我之前从未设置过这样的东西,虽然我最终想出来了,但我不得不将我的解决方案从多个指南/教程中拼凑出来,这些指南做了我的某些方面希望不覆盖整体。特别是,我发现的教程倾向于构建Django可以在其视图中使用的静态Javascript资源。这对于生产来说很好,但是没有热重新加载(即文件更改自动重启服务器,以便它们反映在浏览器中加载的相关页面中)是开发的头发衬衫:起初你认为你可以忍受轻微的不适,但持续的瘙痒会让你疲惫不堪,成为你每一个清醒思想的焦点,驱使你分心,质疑你在生活中的所有选择。想象一下,必须运行一个构建命令,每次更改一行代码时,可能需要一分钟。侧面项目并不完全需要最佳生产力,但是,与工作不同,如果它们变得很麻烦,那么退出就很容易。
我们要做什么
- 创建一个在Docker容器内运行的Django应用程序。
- 使用在Docker容器内运行的字面名称为Create React App的React应用程序创建。
- 在Docker Compose中将这些dockerized应用程序实现为服务。
- 将前端服务连接到可从中获取数据的基本后端API。
注意:本教程假设您熟悉Docker,Django和React,以便专注于在开发环境中将这三个内容协同工作的细节。
1.创建一个dockerized Django应用程序
让我们首先创建一个名为你想要的项目目录,然后创建一个 后端
带子目录的子目录 requirements.txt
只是添加了 Django的
包现在。这将允许我们在使用以下内容构建的Docker镜像中安装和运行Django Dockerfile
:
#使用官方Python运行时作为父图像FROM python:3.6#添加后端目录以使各个服务的绝对文件路径保持一致WORKDIR / app / backend#安装Python依赖项COPY requirements.txt / app / backend RUN pip3 install --upgrade pip - r requirements.txt#添加其余代码COPY。 / app / backend#使端口8000可用于应用程序EXPOSE 8000#确保使用0.0.0.0作为Docker容器内的主机,#否则浏览器将无法找到它CMD python3 manage.py runserver 0.0。 0.0:8000
在终端中,运行以下命令来构建映像,创建名为hello_world的Django项目,然后运行应用程序:
码头工人建造 -t 后端:最新的后端docker run -v $PWD/ backend:/ app / backend backend:最新的django-admin startproject hello_world 。 码头运行 -v $PWD/后端:/应用/后端 -p 8000:8000后端:最新
请注意,我们为此创建了一个成交量 后端
目录,所以创建的代码 startproject命令
将出现在我们的机器上。该 。
在create命令的末尾,将所有Django文件夹和文件放在我们的后端目录中,而不是创建一个新的项目目录,这会使管理Docker容器中的工作目录变得复杂。
打开浏览器 本地主机:8000
验证应用程序是否已启动并正在运行。
2.创建一个dockerized Create React App(CRA)应用程序
虽然我开始编写前端Javascript编码,但我发现我的调用工作在后端系统上。因此,通过结合我自己的渎职和前端工具和技术的快速变化,我没有能力从头开始设置现代前端应用程序。但是,我完全有能力安装软件包并运行命令。
与Django应用程序不同,我们无法同时使用CRA应用程序创建Docker镜像,因为我们首先需要一个 Dockerfile
与节点,所以我们可以初始化CRA应用程序,然后我们将能够添加通常 Dockerfile
用于安装依赖项的命令。所以,创建一个 前端
带有一个目录 Dockerfile
看起来如下:
#使用官方节点运行时作为父图像FROM节点:8 WORKDIR / app /#Install dependencies#COPY package.json yarn.lock / app / #RUN npm install#添加其余客户端代码COPY。 / app / EXPOSE 3000#CMD npm start
一些命令当前已被注释掉,因为我们没有引用一些文件,但稍后我们将需要这些命令。在终端中运行以下命令以构建映像,创建应用程序并运行它:
码头工人建造 -t 前端:最新的前端码头运行 -v $PWD/ frontend:/ app frontend:最新的npx create-react-app hello-world MV 前端/您好世界/* 前端/ hello-world / .gitignore前端/ && 命令rmdir 前端/ hello-world docker run -v $PWD/前端:/应用程序 -p 3000:3000前端:最新的npm开始
请注意,我们将新创建的app目录的内容移动到前端目录并将其删除。 Django默认情况下为我们提供了这样做的选项,但我找不到任何建议CRA除了创建自己的目录之外还会做任何事情。解决这个嵌套结构是一种痛苦,所以我发现将所有东西都移到docker-service级别并从那里工作更容易。浏览您的浏览器 本地主机:3000
确保应用程序正在运行。此外,您可以取消注释其中的其他命令 Dockerfile
,以便下次重建映像时将安装任何新的依赖项。
3. Docker-组合成服务
既然我们有两个Docker镜像并且能够在各自的Docker容器中运行应用程序,那么让我们简化使用Docker Compose运行它们的过程。在 泊坞窗,compose.yml
,我们可以定义我们的两个服务, 前端
和 后端
,以及如何运行它们,这将允许我们巩固多重 搬运工人
命令及其多个参数少得多 泊坞窗,撰写
命令。配置文件如下所示:
版: “3.2" 服务: 后端: 建立: ./backend 成交量: - ./backend:/app/backend 港口: - “8000:8000" stdin_open: 真正 TTY: 真正 命令: python3 manage.py runserver 0.0.0.0:8000 前端: 建立: 。/前端 成交量: - ./frontend:/app #单向成交量,用于从图像内部使用node_modules - /应用/ node_modules 港口: - “3000:3000" 环境: - NODE_ENV =发展 依赖于取决于: - 后端 命令: npm开始
我们已经将docker命令的各种参数转换为配置文件中的键值对,现在我们可以通过执行来运行我们的前端和后端应用程序 码头工人组成
。有了它,你应该能够看到它们并行运行 本地主机:8000
和 本地主机:3000
。
4.将两端连接到一个应用程序
当然,这篇文章的目的不是要学习如何过度复杂地运行独立的React和Django应用程序,只是为了它的乐趣。我们在这里构建一个集成的应用程序,其中包含一个动态的现代前端,该前端使用来自强大的后端API的数据。为了实现这个目标,尽管仍然保持应用程序尽可能简单,让我们让前端向后端发送文本,这将返回文本中字符数的计数,然后前端将显示。
设置Django API
让我们首先为前端调用创建一个API路由。您可以通过在终端中运行以下命令来创建一个新的Django应用程序(这是Django项目架构中的一个子应用程序/模块):
docker-compose run --rm backend python3 manage.py startapp char_count
这为您提供了一个新目录 后端
叫 char_count
,我们可以定义路线及其相关逻辑。
我们可以在中创建API响应 后端/ char_count / views.py
如下所示,按照承诺,将返回提交文本的字符数:
从 django.http 进口 JsonResponse 高清 char_count(请求): 文本 = 请求。得到。得到(“文本”, “”) 返回 JsonResponse({“计数”: LEN(文本)})
现在,为了让Django项目了解我们的新应用程序,我们需要更新 INSTALLED_APPS
在 后端/程序hello_world / settings.py
通过增加 “char_count.apps.CharCountConfig”
到列表。要将我们的计数响应添加到可用的URL,我们会更新 后端/程序hello_world / urls.py
我们的char_count视图如下:
从 django.contrib中 进口 管理 从 django.urls 进口 路径 从 char_count.views 进口 char_count URL模式 = ( 路径(“管理/”, 管理。现场。网址) 路径('char_count', char_count, 名称='char_count') )
由于我们正在更改项目设置,我们需要停止我们的Docker Compose进程(ctl + c或 码头工人组成停止
在一个单独的选项卡中)并再次启动它 码头工人组成
。我们现在可以去 localhost:8000 / char_count?text = hello world
并看到它有11个字符。
将React连接到API
首先,让我们添加更多的甜蜜配置,以确保我们不会得到与我们真正宁愿不处理的网络相关的无声错误。我们的Django应用目前不会在除主机之外的任何主机上运行 本地主机
,但我们的React应用程序只能通过Docker服务名称访问它 后端
(它做了一些神奇的主机映射的东西)。所以,我们需要补充一下 “后端”
至 ALLOWED_HOSTS
在 后端/程序hello_world / settings.py
,我们补充说 “proxy”:“http:// backend:8000”
至 的package.json
。这将允许两个服务相互通信。此外,我们还需要使用npm包 爱可信
要进行API调用,请将其添加到 的package.json
并使用以下内容重建图像:
docker-compose run - R M 前端npm添加axios docker-compose down docker-compose up - 建立
不可否认,我的前端开发技能是次要的,但请记住,下面的小部分并不反映我对React(甚至HTML)的了解。为了简单起见,我刚刚删除了CRA样板并将其替换为输入,按钮,单击处理程序和标题。
进口 应对 从 “反应”; 进口 爱可信 从 “爱可信”; 进口 ” ./App.css'; 功能 handleSubmit(事件) { 常量 文本 = 文献。querySelector(“#炭输入”)。值 爱可信 。得到(`/ char_count?文=${文本}`)。然后(({数据}) => { 文献。querySelector(“#字符数”)。的textContent = `${数据。计数} 字符` }) 。抓住(呃 => 安慰。日志(呃)) } 功能 应用() { 返回 ( <DIV 班级名称=“APP”> <DIV> <标签 htmlFor=“字符输入”>怎么样 许多 人物 不</标签> <输入 ID=“字符输入” 类型='文本' /> <按键 的onClick={handleSubmit}>有?</按钮> </ DIV> <DIV> <H3 ID=“字符数”> </ H3> </ DIV> </ DIV> ); } 出口 默认 应用;
现在,当我们在输入中输入文本并单击按钮时,文本的字符数将显示在下方。最重要的是:我们在现场上下热重装您可以向前端添加新组件,向后端添加新类,所有更改(缺少配置或依赖项)将在您工作时反映在应用程序的功能中,而无需手动重新启动服务器。
摘要
最后,设置所有这些并不是太复杂,但是有很多小问题,其中许多都没有给你一个很好的错误信息来查找Stack Overflow。此外,至少在我的情况下,我真的很挣扎,首先要概念化这些碎片是如何协同工作的。 React应用程序是否会进入Django应用程序,就像它一样 webpacker
在Rails?如果这两个应用程序是单独的Docker Compose服务,您如何连接它们?最后我们学会了如何:
- 在Docker容器中设置Django。
- 在Docker容器中设置Create React App
- 使用Docker Compose配置这些容器
- 使用Docker Compose的服务名称(例如
后端
)和的package.json
的“代理”
属性将React的HTTP调用指向Django的API并显示响应。