写点什么

如何使用本地 Docker 更好地开发?我们总结了这八条经验

  • 2022-05-19
  • 本文字数:2705 字

    阅读完需:约 9 分钟

如何使用本地Docker更好地开发?我们总结了这八条经验

如果你像我们一样需要运行许多不同的应用程序,那么将开发环境容器化可以极大地提高工作效率。这里有一些可以优化本地 Docker 环境的技巧。

 

在 Viget,Docker 已经成为本地开发不可或缺的工具。我们的团队构建和维护着大量的应用程序,运行着不同的软件栈和版本,并且能够将开发环境打包,这让不同项目的切换和开发人员快速上手新项目变得非常容易。这并不是说在本地使用 Docker 开发就没有缺点,但它带来的便利远远超过了缺点。

 

随着时间的推移,我们总结出了自己的一套最佳实践,可以有效设置 Docker 开发环境。请注意最后一点(“本地开发”)——如果你是为了部署而创建镜像,那么这些原则中的大多数都不适用。我们的开发环境一般包括(通过 Docker Compose 编配):

 

  • 应用程序(例如 Rails、Django 或 Phoenix);

  • JavaScript 监视器/编译器(例如 webpack-dev-server);

  • 数据库(通常是 PostgreSQL);

  • 其他必要的基础设施(如 Redis、ElasticSearch、Mailhog);

  • 有些应用程序实例偶尔也会做一些其他的事情,而不只是运行开发服务器(比如后台任务)。

 

基于这样的架构,以下是我们试图进行标准化的最佳实践。

 

不要将代码或应用级的依赖项放入镜像中

 

你的主 Dockerfile 文件,也就是运行应用程序所需的文件,应该包含运行应用程序所需的所有软件,但不应该包含应用程序代码本身——当 docker-compose run 命令开始执行时,它们将被挂载到容器中,并在容器和本地机器之间进行同步。

 

另外,区分系统级依赖项(如 ImageMagick)和应用级依赖项(如 Rubygems 和 NPM 包)也很重要——前者应该包含在 Dockerfile 中,后者不应该。将应用级依赖项放到镜像中意味着每次有人添加新依赖项时都必须重新构建镜像,这既耗时又容易出错。相反,我们应该将这些依赖项作为启动脚本的一部分。

 

非必要不使用 Dockerfile

 

基于第一点,你可能会发现根本不需要编写 Dockerfile 文件。如果你的应用程序没有任何特殊的依赖项,可以将 docker-compose.yml 的入口指向官方的 Docker 仓库(如 ruby:2.7.6)。这样做并不常见——大多数应用程序和框架都需要一定数量的镜像基础(例如,Rails 需要 Node),但如果你发现自己的 Dockerfile 只包含一个 FROM 行,你就可以不使用这个文件。

 

只在 docker-compose.yml 中引用一次 Dockerfile

 

如果你将同一个镜像用于多个服务(你应该这么做),只需要在一个服务的定义中提供构建说明,给它起一个名字,然后在其他服务中引用这个名字。举个例子,假设有个 Rails 应用程序使用一个共享的镜像来运行开发服务器和 webpack-dev-server,那么配置可能像这样:

 

services:  rails:    image: appname_rails    build:      context: .      dockerfile: ./.docker-config/rails/Dockerfile    command: ./bin/rails server -p 3000 -b '0.0.0.0'

node: image: appname_rails command: ./bin/webpack-dev-server
复制代码

 

这样,当我们在构建服务(使用 docker-compose)时,镜像就只构建一次。如果我们省略 image:指令同时复制 build:,就会构建完全相同的镜像两次,这样会浪费磁盘空间和有限的时间。

 

在命名卷中缓存依赖项

 

正如第一点所提到的,我们不会将代码依赖项放到镜像中,而是在启动时安装它们。可以想象的是,如果我们每次重启服务时都从头开始安装 gem/pip/yarn 这样的库,速度会非常慢,所以我们使用 Docker 的命名卷来保持缓存。上面的配置可能会变成这样:

 

volumes:  gems:  yarn:  services:  rails:    image: appname_rails    build:      context: .      dockerfile: ./.docker-config/rails/Dockerfile    command: ./bin/rails server -p 3000 -b '0.0.0.0'    volumes:      - .:/app      - gems:/usr/local/bundle      - yarn:/app/node_modules

node: image: appname_rails command: ./bin/webpack-dev-server volumes: - .:/app - yarn:/app/node_modules
复制代码

 

命名卷的挂载点可能因不同的软件栈而异,但原则是差不多的:将编译后的依赖项保存在已命名的卷中,以大幅缩短启动时间。

 

将临时的东西放入命名卷中

 

上一点提到使用命名卷来提高性能,这里有另一个有用的技巧:将保存只读文件的目录放入命名卷中,阻止它们被同步回本地机器(这会带来很大的性能开销),特别是 log 和 tmp 目录,以及应用程序存储上传文件的地方。

 

根据经验,如果一个目录出现在.gitignore 中,那么最好把它放入命名卷中。

 

在 apt-get 更新后进行清理

 

如果在 Dockerfiles 中引用了基于 Debian 的镜像,你就必须运行 apt-get update,然后才能通过 apt-get install 安装依赖项。如果不做一些处理,一堆额外的数据会被放到镜像中,极大增加了镜像的体积。

 

我们的最佳实践是在一个 RUN 命令中执行更新、安装和清理操作:

 

RUN apt-get update && \  apt-get install -y libgirepository1.0-dev libpoppler-glib-dev && \  rm -rf /var/lib/apt/lists/*
复制代码

 

使用 exec 而不是 run

 

如果需要在容器中运行命令,你有两个选项:run 和 exec。前者将启动一个新容器来运行命令,而后者将连接到一个已经在运行中的容器。

 

在大多数情况下,假设在开发应用程序时总是有其他服务在运行,那么 exec(特别是 docker-compose exec)就是你所需要的,因为它运行起来更快,而且不会留下任何奇怪的文件(如果你忘了在 run 中包含--rm 标志,就会发生这种情况)。

 

使用 wait-for-it 协调服务

 

如果使用了之前提到的共享镜像和依赖项命名卷,你可能会遇到这样的问题:一个服务会在另一个服务的入口点脚本执行完毕之前启动,从而导致发生了错误。当出现这种情况时,我们可以引入wait-for-it脚本,它将向一个 Web 地址发起请求,当这个地址返回响应时再执行命令。

 

所以,我们把 docker-compose.yml 修改一下:

 

volumes:  gems:  yarn:  services:  rails:    image: appname_rails    build:      context: .      dockerfile: ./.docker-config/rails/Dockerfile    command: ./bin/rails server -p 3000 -b '0.0.0.0'    volumes:      - .:/app      - gems:/usr/local/bundle      - yarn:/app/node_modules

node: image: appname_rails command: [ "./.docker-config/wait-for-it.sh", "rails:3000", "--timeout=0", "--", "./bin/webpack-dev-server" ] volumes: - .:/app - yarn:/app/node_modules
复制代码

 

这样,在 Rails 开发服务器完全启动并运行之前,webpack-dev-server 是不会启动的。

 

以上就是我们在过去几年中总结的一些 Docker 最佳实践,我们也将努力保持更新这个清单。

 

原文链接:

 

https://www.viget.com/articles/local-docker-best-practices/

 

2022-05-19 21:036104

评论

发布
暂无评论
发现更多内容

DeFi 协议应提供多类封装型比特币, wBTC 不应作为唯一选择

TechubNews

SVN管理工具Cornerstone for mac永久破解版 及Cornerstone详细使用教程

理理

望繁信科技邀您共赴2024数博会,开启数智经济新篇章

望繁信科技

大数据 数字化转型 流程挖掘 大数据博览会 流程智能

全球首发!昆仑万维重磅推出AI流媒体音乐平台Melodio

新消费日报

强大的视频下载工具4K Video Downloader for Mac中文激活版

Mac相关知识分享

视频下载 Mac软件 视频下载工具

4家手机云电脑玩游戏:ToDesk云电脑、易腾云、达龙云、青椒云实测对比

小喵子

云电脑 云游戏 ToDesk ToDesk云电脑 云电竞

助力人效提升!火山引擎数智平台助推头部新能源车企业务增长

字节跳动数据平台

大数据 云服务 BI 数据可视化 物化视图

PDF编辑软件 Acrobat DC 2023中文直装下载 【mac&win】

理理

【mac 软件推荐】SecureCRT for mac(终端SSH工具)永久激活

理理

ForkLift for Mac(文件管理程序)v4.1.6激活版

Mac相关知识分享

Mac软件 文件管理程序

VM虚拟机VMware Fusion Pro 13:打破界限,实现多平台的无缝融合

理理

NCH WavePad for Mac(强大的mac音频编辑软件) v19.55注册版

Mac相关知识分享

视频编辑器

运维实战来了!如何构建适用于YashanDB的Prometheus Exporter

YashanDB

yashandb 崖山数据库 崖山DB

聊一聊 Netty 数据搬运工 ByteBuf 体系的设计与实现

bin的技术小屋

Netty java netty netty内存管理

LLM大模型部署实战指南:Ollama简化流程,OpenLLM灵活部署,LocalAI本地优化,Dify赋能应用开发

汀丶人工智能

人工智能 ollama localAI openllm

GreatSQL 并行Load Data加快数据导入

GreatSQL

macOS和Windows系统代码编辑器 Sublime Text 中文设置教程分享

理理

代码编辑工具 sublime text Sublime Text 4注册版

JProfiler for Mac(Java开发分析软件) v14.0.0永久激活版

理理

cad2024安装教程分享 Autodesk AutoCAD 2024 v2024.3中文版 附破解补丁

理理

什么是 OpenSSL?

NGINX开源社区

https TLS ssl 开源安全 openssl

宠物供应链服务平台如何实现云化架构升级改造?

华为云开发者联盟

数据库 存储 企业号 8 月 PK 榜 企业号2024年8月PK榜

AI提问实现学习弯道超车!如何使用AI加速学习?

可信AI进展

人工智能

etl 读写 elastic 同步数据

weigeonlyyou

hadoop elastic HBase ETL Go 语言

2024-08-14:用go语言,给定两个长度分别为n和m的整数数组nums和changeIndices,下标从1开始。初始时,nums 中所有下标均未标记。 从第1秒到第m秒,每秒可以选择以下四种操

福大大架构师每日一题

福大大架构师每日一题

让生成式 AI 触手可及:火山引擎推出 NVIDIA NIM on VKE 最佳部署实践

Geek_2d6073

企业建设零信任体系的核心思路

芯盾时代

身份安全 iam 业务层 零信任模型

Author for Mac(文档编辑工具)

Mac相关知识分享

办公软件 文档编辑软件

Postbox for Mac(邮件客户端)v7.0.62激活版

Mac相关知识分享

邮件管理 Mac软件

苹果电脑如何安装Windows11系统?借助PD虚拟机,mac电脑也能安装Win11了!

理理

阿里云Elasticsearch 企业级AI搜索方案发布

阿里云大数据AI技术

人工智能 elasticsearch 搜索 rag

亚信安慧AntDB数据库与实在智能完成兼容性互认证,携手助力企业数据安全

亚信AntDB数据库

AntDB

如何使用本地Docker更好地开发?我们总结了这八条经验_语言 & 开发_David Eisinger_InfoQ精选文章