我有几个与Docker在开发阶段的使用相关的问题。
我将提出我认为Docker如何在开发环境中使用的三种不同场景。让我们想象一下,我们正在Java和Spring Boot中创建一个REST API。为此,我需要一个MySQL数据库。
>
第一个场景是让docker compose使用MySQL容器进行开发,生产docker使用MySQL和另一个容器中的Java应用程序(jar)进行组装。为了开发,我启动docker-compose-dev.yml,只启动数据库。应用程序是使用IDE启动和调试的,例如IntelliJ Idea。对代码所做的任何更改,IDE都将通过应用更改来识别并重新启动应用程序。
第二个场景是,对于开发环境和生产环境,docker由数据库和应用程序容器组成。这样,每次我对代码进行更改时,我都必须重建图像,以便将更改加载到图像中,并再次启动容器。这个场景可能是最典型的,用于Docker的开发,但它似乎非常缓慢,因为每次发生更改时都需要重建映像。
第三种情况是前两种情况的混合。两个码头工人。development docker compose包含这两个容器,但具有允许实时重新加载应用程序、映射卷和使用Spring开发工具等的机制。通过这种方式,容器被启动,如果文件发生任何更改,应用程序容器将检测到有更改,并将重新启动。对于生产,docker compose将仅使用两个容器创建,但没有实时重新加载功能。在我看来,这将是理想的情况,但我认为这非常依赖于所使用的技术,因为并非所有技术都允许实时重新加载。
问题如下。
>
在阶段使用Docker时,以下哪种情况最典型?
情景1是否得到了很好的解决?也就是说,只对数据库、队列等外部服务进行Docker化,并使用IDE执行应用程序的开发和调试,而不使用Docker。
我提出的疑问和场景是在我提出场景2的问题之后出现的。随着代码的每次更改,必须重建映像并再次启动容器是对时间的重大浪费。简而言之,一个问题是:如何避免这种情况?
提前感谢您抽出时间。
注意:这可能是一个取决于意见的问题,但了解开发人员通常如何处理这些问题会很好。
我见过它们在不同的场景中使用。有一些陷阱需要避免:
>
主机卷的文件权限可能会很复杂,具体取决于您的docker版本。一些较新的Docker Desktop安装会自动处理uid映射,但如果直接在Linux上开发,则需要确保容器与主机用户以相同的uid运行。
如果容器未映射到主机卷,请避免在容器内进行更改,因为重新创建容器时,这些更改将丢失。
下面是我对每个选项的评估:
>
仅对DB进行容器化:当开发人员已经拥有用于选择语言的开发环境时,这很有效,并且没有外部依赖关系蔓延的风险,例如开发人员将他们的JDK安装升级到比构建映像时更新的版本。它遵循首先容器化依赖项的想法,同时也为开发人员提供熟悉的IDE与他们的应用程序集成。
为每次更改重建映像:对于开发人员工作流来说,这往往是最不理想的,但在您不熟悉该工具时,这是最快实现的。我将给出第四个选项,我认为这是一个改进。
容器中的所有内容、卷装载和实时重新加载:这是最复杂的实现,需要语言本身支持实时重新加载等功能。然而,当他们这样做时,对于开发人员来说几乎是天衣无缝的,可以让他们快速地完成一个新项目,而无需安装任何其他工具即可开始。
在容器中使用卷装载重建应用程序:这是2和3之间的中间点。如果没有实时重新加载,则可能需要重新编译或重新启动解释器以查看任何更改。我没有重建图像,而是将重新编译步骤放在开发图像的入口点。我将把代码装载到容器中,并运行完整的JDK,而不仅仅是JRE(或任何需要的编译器)。我将命名卷用于任何依赖项缓存,因此它们不需要在每次重新启动时下载。然后,查看更改的方法是重新启动该容器。这些步骤与在容器外编译二进制文件、停止旧服务、重新编译并重新启动服务的步骤相同,但现在它发生在一个容器内,该容器应具有构建生产映像时使用的相同工具。
对于选项4,我倾向于使用多阶段构建,其中包含构建、开发和发布阶段。构建阶段会引入代码并对其进行编译,开发阶段与构建阶段的基本映像相同,但有一个执行编译/运行的入口点,发布阶段会将构建阶段的结果复制到最小的运行时。然后,开发人员将拥有一个用于开发的撰写文件,该文件将创建开发映像,并在卷装载和所有调试端口打开的情况下运行该映像。
我在我的Web开发中使用了类似于您的第三个场景的东西,但它是基于节点的。所以我有3个docker-compose文件(实际上是4个,一个是base,并且为其他人提供所有常见的东西)用于开发、登台和生产环境。
暂存docker compose配置类似于生产配置,不包括SSL、端口和其他可能不允许在本地使用的内容。
我为每个服务都有一个单独的容器(比如DB、queue),对于dev,我也有额外的dev DB和queue容器,主要用于运行自动测试。在dev环境中,所有源代码都装入容器中,因此它允许在容器外部使用IDE/编辑器,并查看内部的更改。
我使用supervisor来管理容器中的工人,并在需要时使用一些命令手动重新启动工人。也许你可以做一些类似于重新html" target="_blank">编译/重启Java应用的事情。或者,如果你知道如何组织应用程序源代码更改检测和应用程序自动重新加载,那么这可能是最好的变体。顺便说一句,你给了我一个想法,让我研究一些类似的适合我的情况。
对于暂存和生产环境,我的源代码包含在使用生产Dockerfile的相应容器中。我有一些命令,可以使用我需要的环境重新启动所有东西,这通常包括重建容器,但由于Docker缓存,它不需要太多时间(大约20秒)。考虑到在不同环境之间切换不是一个太频繁的操作,我对此感到非常舒服。
Production docker compose config仅在部署期间使用,因为它支持SSL、正确的端口,并具有一些额外的生产功能。
以下是我在项目中使用它的方式:
我与安装主管的Dockerfile的一部分:
FROM node:10.15.2-stretch-slim
RUN apt-get update && apt-get install -y \
# Supervisor
supervisor \
...
...
# Configs for services/workers managed by supervisor
COPY some/path/worker-configs/*.conf /etc/supervisor/conf.d/
这是工人的Supervisor配置之一的示例:
[program:myWorkerName]
command=/usr/local/bin/node /app/workers/my-worker.js
user=root
numprocs=1
stopsignal=INT
autostart=true
autorestart=true
startretries=10
在本例中,命令
应该运行Java应用程序。
这是一个命令别名的例子,便于从容器外部管理主管。我使用Makefile作为所有命令的通用运行程序,但这可能是另一回事。
# Used to run all workers
su-start:
@docker exec -t MY-WORKERS-CONTAINER-NAME supervisorctl start all
# Used to stop all workers
su-stop:
@docker exec -t MY-WORKERS-CONTAINER-NAME supervisorctl stop all
# Used to restart all workers
su-restart:
@docker exec -t MY-WORKERS-CONTAINER-NAME supervisorctl restart all
# Used to check status of all workers
su-status:
@docker exec -t MY-WORKERS-CONTAINER-NAME supervisorctl status
如上所述,这些管理器命令需要手动运行,但我认为可以实现另一个基于节点的工作程序或容器外的一些观察程序,这些工作程序将检测源目录的文件系统更改,并自动运行这些命令。我认为用Java实现类似的东西是可能的,就像这样。
另一方面,它需要小心地进行,以避免在每个微小的变化中不断地重新启动工人。
免责声明:这是我自己对马尔斯先生提出的问题的看法。尽管我尽了最大努力用真实的来源来支持我的答案,但这主要是基于我自己的经验和一点常识
使用Docker进行开发时,以下哪种情况最典型?
我在几个项目中看到了所有3个场景,每个场景都有各自的优缺点。但是我认为场景3允许动态代码重新加载,在灵活性和一致性方面是最有利的:
情景1是否得到了很好的解决?也就是说,只对数据库、队列等外部服务进行Docker化,并使用IDE执行应用程序的开发和调试,而不使用Docker。
场景1非常常见,但IDE环境可能与Docker容器中的环境不同(并且很难为IDE环境和Docker环境中的每个LIB、依赖项等维护版本匹配)。它可能还需要在开发人员和生产人员之间进行一个中间步骤,以便在开发人员开始工作后,在投入生产之前实际测试Docker映像。
根据我自己的经验,如果你在实际开发时不想与Docker打太多交道,或者你使用的语言或技术不适合场景3中描述的动态重新加载,那么这样做非常好。但最终,这只会增加环境之间的偏差,以及开发人员和产品部署方法之间的复杂性。
必须重建图像并重新启动容器是一种严重的时间浪费。简而言之,一个问题是:如何避免这种情况?
除了您描述的场景之外,您还可以通过利用Docker构建缓存和设计Dockerfile来体面地(甚至大幅地)减少映像构建时间。例如,Python应用程序通常会将代码复制为构建的最后(或几乎最后)一步,以避免使缓存无效,对于Java应用程序,可以拆分代码,以避免每次代码更改时编译整个应用程序——这将取决于您的实际设置。
我个人使用与场景3大致匹配的工作流,例如:
docker-compose.yml
file corresponding to my Production environmentdocker-compose.dev.yml
which will override some aspect of my main Docker Compose file such as mouting code from my machine, adding dev specific flags to commands, etc. - it would be run such as docker-compose -f docker-compose.yml -f docker-compose.dev.yml
我可以禁用POM中的特定阶段:Maven生命周期中的禁用阶段。可以从命令行禁用test:是否可以从特定阶段开始mvn生命周期,例如只使用命令行选项编译?
DevOps是开发和运营之间的深度集成。在不了解DevOps生命周期的情况下,无法理解DevOps。 以下是有关连续 DevOps生命周期的简要信息: 1. 开发 在这个DevOps阶段,软件的开发不断发生。在此阶段,整个开发过程分为小的开发周期。这有利于DevOps团队加快软件开发和交付过程。 2. 测试 QA团队使用Selenium等工具来识别和修复新代码中的错误。 3. 整合 在此阶段,新功
Flex应用程序的生命周期 虽然,您可以在不了解应用程序的生命周期阶段的情况下构建Flex应用程序,但了解基本机制是很好的。 事情发生的顺序。 它将帮助您配置功能,例如在运行时加载其他Flex应用程序,以及管理在运行时加载和卸载类库和资产的过程。 充分了解Flex应用程序生命周期将使您能够构建更好的应用程序并对其进行优化,因为您将知道在何处优化运行代码。 例如,如果您需要确保在预加载器期间运行某些
这在我做项目的笔记本电脑上工作,而在另一台笔记本电脑上抛出一个错误。错误代码为 格式:或:[:]:.可用的生命周期阶段有:验证、初始化、生成源、过程源、生成资源、过程资源、编译、过程类、生成测试源、过程测试源、生成测试资源、过程测试资源、测试编译、过程测试类、测试、准备包、包、集成前测试、集成测试、集成后测试、验证、安装、部署、预清理、清理、清理后、站点前、站点后、站点部署。->[帮助1][ERR
我已经用maven创建了一个java项目。在我的项目(src/main/resources下)中,有一些资源文件我想复制到目标/类中。 我在pom xml中添加了以下行: 当我运行mvn资源时:通过命令行获取的资源文件正在复制到目标/类中(因此生命周期中的资源阶段正在工作)。然而,当我在cmd中输入mvn install:install时,资源文件并没有被复制到目标/类中。 我得到: 生命周期中的
如何禁用Maven3默认生命周期中不需要的阶段? 例如,我希望、和阶段永远不会发生,并将我的构建日志从以下内容转变为: 变成这样: