为什么选择 Docker?用 Docker 创建多容器应用程序
如果你刚开始学习 Docker,你可能会经常想到的一个问题是 Docker 是什么以及为什么需要它。
在这篇文章中,我将对其中一些问题提供一些基本解答,并最终指导你使用 Docker-Compose 构建你的第一个多容器应用程序。
目录
- Docker 及其原因
- Docker 镜像
- Docker compose
- 使用 docker-compose 构建多容器应用程序
- 进一步阅读
Docker 以及为什么?
我个人最喜欢的关于 docker 的定义是由 docker 团队提供的定义,他们将 docker 定义为一个开放平台,供开发人员和系统管理员构建、交付和运行分布式应用程序,无论是在笔记本电脑、数据中心虚拟机还是云端。
保持一致的环境很困难
如果没有虚拟化技术,应用程序就无法保证其工作方式与在特定环境中完全相同。这主要是由于环境不一致以及系统库的差异造成的。
您可能只使用生产环境来开发应用程序,python3
但发现生产环境正在运行python2
。如果您无法升级到生产环境,情况就会变得有点复杂,python3
因为主机上还有其他应用程序需要python2
运行。
开发人员花费数小时努力寻找解决不一致环境的解决方案,但大多数时候,他们出色的代码仍然无法运行,因为一个库文件已经过时了。
斗争永无止境。我曾经经历过这种痛苦,因为要排除某个功能在一个环境中运行良好,而在另一个环境中却不行。是啊!它在我们的机器上总是运行良好,但在生产环境中——从来就不行!:(
在本地机器上安装应用程序依赖项需要时间
如果没有虚拟化,搭建开发环境可能会非常困难,我们经常需要安装不同版本的软件来支持我们正在开发的各种服务。维护不同版本的 PHP 或 MySQL 数据库可能会耗费你大量的时间,而这些时间本可以用来编写代码。
容器和虚拟机解决了这个问题,并通过将您的应用程序及其依赖项隔离到可以在任何地方可靠运行的单个独立单元中来减轻您的压力。
虽然虚拟机和容器的目标是一样的,但是容器由于轻量、速度快、资源利用率低等优点,比虚拟机更受青睐。
这里的集装箱功能类似于你在高速公路上看到的集装箱:它们都是用来装产品的容器。区别在于它们装的东西。我们的集装箱装的是软件产品。
Docker是少数几个流行的容器提供商之一,在接下来的几段中,我们将详细探讨如何将您的开发环境 docker 化。
Docker 镜像
Docker 容器由 Docker 镜像构建而成。镜像是一种惰性且不可变的文件,本质上是容器的快照。我倾向于将 Docker 容器视为 Docker 镜像的一个运行实例。
图像的构建Dockerfile
基本上是一个文本文档,其中包含有关 docker 如何构建图像的说明。
Docker compose
Docker-compose是一款帮助您运行复杂应用程序的工具。
一个可运行的软件绝非孤岛,它很可能依赖于一系列其他组件,例如数据库、缓存甚至其他服务。最佳实践是将每个组件都放在各自的容器中。使用 docker-compose,您可以在单个文件中定义一个多容器应用程序,并通过单个命令启动它。
使用 docker-compose 构建多容器应用程序
在这篇文章变得冗长难耐之前,让我们开始动手吧。
如果你还没有安装 docker 和 docker-compose,请点击此处查看安装说明。
我们将为我们的项目组合多个服务。这是一个 Laravel 应用程序,使用 MySQL 数据库和 Redis 进行缓存。
### 开始一个新的 Laravel 项目
通过运行启动 Laravel 项目composer create-project --prefer-dist laravel/laravel laravelApp
如果一切正常,您的目录应该看起来像这样。
### 为 Web 服务器 (Nginx) 创建 Dockerfile
我们需要一个 Web 服务器 (nginx) 来提供静态内容。我们创建一个 Dockerfile,Dockerfile
它本质上是一个文本文件,其中包含 Docker 如何构建镜像的说明。
在项目根目录下,我们创建一个web.docker
包含以下内容的文件。
# /project/root/web.docker
# start building image from nginx 1.13
FROM nginx:1.13
# copy site.conf from local directory to /etc/nginx/conf.d/default.conf
ADD ./site.conf /etc/nginx/conf.d/default.conf
WORKDIR /var/www
site.conf
包含 nginx 的虚拟主机配置
在项目根目录下,site.conf
使用此内容创建
# /project/root/site.conf
server {
listen 80;
index index.php index.html;
access_log /var/www/storage/logs/access.log;
error_log /var/www/storage/logs/error.log;
root /var/www/public;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,api_key' always;
add_header 'Access-Control-Allow-Methods' 'POST, GET, PUT, DELETE' always;
}
}
为 PHP 7.1 创建 Dockerfile
Laravel 需要 PHP 以及一些特定的 PHP 扩展才能运行。我们创建一个同名文件,app.docker
其中包含所需的 PHP 版本和扩展。
同样在项目根目录下创建该文件。
FROM php:7.1.9-fpm
# Install any custom system requirements here
RUN apt-get update && apt-get install -y libmcrypt-dev zip unzip git mysql-client \
&& docker-php-ext-install mcrypt pdo_mysql
WORKDIR /var/www
至于 MySQL 数据库和 Redis,预建的镜像足以满足本次演示的需求。我们无需对其进行自定义。
在 Docker-compose 文件中定义服务
现在,我们创建一个docker-compose.yml
。它应该位于项目的根目录中。
version: '2'
services:
web:
build:
context: ./
dockerfile: web.docker
container_name: web
ports:
- "8080:80"
volumes:
- ./:/var/www
links:
- app
app:
build:
context: ./
dockerfile: app.docker
volumes:
- ./:/var/www
depends_on:
- mysql
- redis
environment:
- "APP_ENV=${APP_ENV}"
- "APP_DEBUG=${APP_DEBUG}"
- "APP_KEY=${APP_KEY}"
- "DB_CONNECTION=${DB_CONNECTION}"
- "DB_HOST=${DB_HOST}"
- "DB_PORT=${DB_PORT}"
- "DB_DATABASE=${DB_DATABASE}"
- "DB_USERNAME=${DB_USERNAME}"
- "DB_PASSWORD=${DB_PASSWORD}"
- "CACHE_DRIVER=${CACHE_DRIVER}"
- "QUEUE_DRIVER=${QUEUE_DRIVER}"
- "REDIS_HOST=${REDIS_HOST}"
- "REDIS_PASSWORD=${REDIS_PASSWORD}"
- "REDIS_PORT=${REDIS_PORT}"
mysql:
image: mysql:5.7
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:3.0
ports:
- "6379:6379"
volumes:
- ./redis:/data
让我们花一点时间来了解一下上述内容docker-compose.yml
。
version 2
:我们正在使用的 docker-compose 语法的版本。
services
:服务是我们应用程序的不同部分,即(app,redis,mysql)。
build
:它定义一个字符串,其中包含构建上下文的路径和引用我们的 Dockerfile 的 dockerfile 参数
container_name
:用于指定容器构建后的名称
environment
:用于将环境变量传递给容器。
注意: Docker Compose 会将.env中定义的变量添加到服务配置中。这意味着你可以自动访问 .env
.env
文件中的 Laravel 配置docker-compose.yml
。
image
:用于指定开始构建容器的预构建图像。
Ports
:用于将容器的端口映射到主机的端口。在app
服务中,我们将8080
主机上的端口映射到80
容器内的端口。
volumes
:用于将容器目录挂载到主机目录。在本例中,docker 将在服务/var/www
中创建目录app
,并将本地目录中的文件指向该目录。这在开发过程中非常有用,因为如果您对源代码进行了更改,更改将立即生效。
depends_on
:这确保mysql
和在服务redis
之前启动。app
在执行期间,docker-compose 在容器之间构建一个网络,以便每个容器可以使用 中定义的名称相互引用docker-compose.yml
。
创建 DockerIgnore 文件
文件dockerignore
类似于gitignore
文件。使用dockerignore
文件,您可以指定将从构建中排除的文件和文件夹,这些文件将不会被复制到镜像中。
让我们dockerignore
使用下面的代码在根文件夹中创建一个文件
app.docker
web.docker
docker-compose.yml
.env
使用 Compose 构建并运行项目
为了构建项目,我们导航到项目根目录并运行:
docker-compose build
现在,我们可以继续运行我们的服务:
docker-compose up -d
为了验证这些服务确实在运行,我们输入docker ps
命令。这将列出所有正在运行的容器。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7275af6e2f3f laravelapp_web "nginx -g 'daemon of…" 9 seconds ago Up 6 seconds 0.0.0.0:8080->80/tcp web
2ce0817bd07e laravelapp_app "docker-php-entrypoi…" 10 seconds ago Up 8 seconds 9000/tcp laravelapp_app_1
5a85911e6ecd mysql:5.7 "docker-entrypoint.s…" 58 seconds ago Up 11 seconds 0.0.0.0:3306->3306/tcp laravelapp_mysql_1
41739940ec82 redis:3.0 "docker-entrypoint.s…" 58 seconds ago Up 10 seconds 0.0.0.0:6379->6379/tcp laravelapp_redis_1
`
最后,将您的网络浏览器指向http://localhost:8080/
,您应该会看到一个默认的 laravel 主页,如下所示。
由于我们已经将项目目录挂载到应用程序容器的目录,因此对源代码所做的更改会自动应用。
进一步阅读
Docker 速查表
开始使用 Compose
Docker 入门:初学者的关键概念
如果您有任何意见或发现任何 bug,欢迎在这里留言,或在Linkedin上联系我。
文章来源:https://dev.to/abiodunjames/why-docker-creating-a-multi-container-application-with-docker--1gpb