Docker中运行WordPress网站
说明
自Docker诞生以来,在Docker容器中运行WordPress网站已变得越来越流行。这样做有很多明显的好处,特别是对于那些正在开发主题和插件的人。而且,虽然对WordPress网站进行容器化不是一项艰巨的工作,但在生产中构建和运行容器需要考虑许多因素。
在本教程中,将逐步指导我们在生产环境中运行容器的每个步骤,从构建初始映像到在生产环境中安全可靠地运行容器。
入门
运行WordPress容器
WordPress将正式的Docker映像发布到Dockerhub。它是在Alpine Linux上运行的简单,轻巧的容器。将图像下拉到本地存储库中。
"
码头工人拉wordpress
"
请注意,在我们的pull命令中未指定发行版本。当未指定发布标签时,docker pull的默认操作是下拉最新图像(或者<image-name>:latest>。要下拉特定版本的WordPress,请将版本标签添加到docker pull命令中。
"
码头工人拉wordpress:5.2
"
让我们运行基本图像以显示正在运行的容器。我们将使用-p标志在端口80上公开该容器,并使用-d标志守护该容器在后台运行。
"
码头工人运行-d -p 80:80 wordpress
"
对于典型的WordPress安装,我们要执行的第一个操作是配置数据库。基本映像接受许多用于配置WordPress的环境变量。要知道的关键变量是用于配置数据库端点的。
WORDPRESS_DB_HOST
WORDPRESS_DB_USER
WORDPRESS_DB_PASSWORD
WORDPRESS_DB_NAME
docker run -d -p 80:80 -e WORDPRESS_DB_HOST=localhost,WORDPRESS_DB_USER=user1,WORDPRESS_DB_PASSWORD=password,WORDPRESS_DB_NAME=wpsite1 wordpress
Docker提供了一个标志来设置环境变量列表。以下是通过设置数据库相关环境变量来运行基本WordPress映像的示例。
WORDPRESS_DB_HOST= WORDPRESS_DB_USER=... WORDPRESS_DB_PASSWORD= WORDPRESS_DB_NAME= WORDPRESS_TABLE_PREF=wp_
现在,我们不太可能要一遍又一遍地键入。值得庆幸的是,Docker具有通过文本文件设置环境变量的功能。创建一个名为wp_vars的新文件,然后添加以下内容。确保设置值以匹配环境。
docker run -d -p 80:80 --env-file wp_vars wordpress
要在运行WordPress容器时使用环境变量文件,我们使用env-file标志。运行基本映像,然后将env文件指向wp_vars文件。
自定义WordPress图像
我们已成功使用基础映像将WordPress作为Docker容器运行。必须网站不能运行WordPress的原始安装,因此在下一节中,我们将研究为网站自定义图像。
Dockerfile是Docker使用的文件,用于模板化新Docker映像的构建。大多数映像都建立在现有映像之上,以扩展其配置。我们将通过在官方WordPress Docker映像之上为WordPress博客构建新映像来执行相同操作。
mkdir -p ~/workspace/wordpress
在文件系统上创建工作区以存储WordPress Docker项目。
FROM wordpress ENV WORDPRESS_DB_HOST=192.168.1.2:3307 \ WORDPRESS_DB_USER=demo_blog \ WORDPRESS_DB_NAME=demo_blog \ WORDPRESS_TABLE_PREFIX=wp_
在工作空间中,创建一个名为Dockerfile的新文件,然后将以下内容添加到Dockerfile中。
我们的Dockerfile有两个步骤:FROM和ENV。 FROM步骤指示Docker根据wordpress映像构建新映像。 ENV步骤允许我们为WordPress设置环境变量。请注意,我们的Dockerfile中缺少WORDPRESS_DB_PASSWORD变量。在我们的配置文件中存储敏感信息(也称为机密信息)是非常不安全的。相反,我们将在启动容器时设置变量。
docker build -t myblog:1.0.0 .
让我们构建新的自定义图像。我们将使用名称和版本标记图像,以保持更改历史记录。由于这是我们的第一个构建,因此我们将使用myblog:1.0.0标记图像。
docker images
成功构建后,我们的映像将在我们本地的Docker存储库中可用。我们可以通过运行docker images命令来验证这一点。
docker run -d -p 80:80 -e WORDPRESS_DB_PASSWORD=super-secret-password myblog:1.0.0
添加插件和主题
让我们运行第一个图像。我们将使用-e标志设置WordPress数据库密码。或者,我们可以像以前一样使用和环境变量文件。
尽管WordPress的一个普通实例可能会满足某些要求,但大多数都通过其他插件和主题来自定义WordPress。两者都可以通过管理门户安装。但是,由于正在运行的容器是短暂的,所以在停止容器时,所有更改都将丢失。
有两种解决方案。解决方案将在本节中介绍,也就是将插件添加到构建过程中。第二个选项是将永久性存储添加到容器,将在下面的部分中介绍。
Docker提供了用于将内容添加到映像构建ADD和COPY的命令。虽然两者都可以将下载插件和主题添加到WordPress图像,但是ADD命令将自动将存档提取到目标。
mkdir -p ~/workspace/wordpress/{themes,plugins,uploads}
在工作区中创建目录以存储主题和插件,然后将一些主题和插件下载到适当的目录中。
FROM wordpress ENV WORDPRESS_DB_HOST=192.168.1.2:3307 \ WORDPRESS_DB_USER=demo_blog \ WORDPRESS_DB_PASSWORD=d7FfHZsBASsqN5Y \ WORDPRESS_DB_NAME=demo_blog \ WORDPRESS_TABLE_PREFIX=wp_
修改Dockerfile,以将主题和插件添加到映像中的WordPress安装中。对于每一项,我们在本地计算机上指定一个源,然后在映像本身内指定一个目标。
ADD plugins / plugins-a-1.0.0.tar.gz / var / www / html / wp-content / plugins
plugins / plugin-b-1.1.1.tar.gz / var / www / html / wp-content / plugins
"
docker build -t myblog:1.0.1 .
保存所做的更改,然后运行新的版本。如果需要,将图像版本增加一。
docker run -d -p 80:80 -e WORDPRESS_DB_PASSWORD=super-secret-password myblog:1.0.1
运行更新的Docker映像,并验证我们安装的主题和插件是否可用。
将插件和主题添加到构建很方便,但这会带来一些问题。例如,插件通常会发布大量版本来解决错误和安全性问题。我们可以从正在运行的容器中更新插件,但是,由于该容器是临时的,因此在重新启动容器时将不会保留更新。由于更新可能会导致数据库架构更改,因此站点将无法通过过时的容器正确加载。
内容的永久存储
我们可以在每次插件更新时生成一个新的映像构建,除非这可能会成为管理负担。更好的解决方案是将插件和主题存储在持久存储中,该存储在每次启动新容器时都会挂载。我们将在下一部分中讨论该主题。
Docker可以在运行时将主机文件系统上的目录挂载到容器中。此功能允许数据保留在容器的生命周期之外,该生命周期是临时的(临时的)。借助批量功能,我们可以将插件和主题安装在本地主机的文件系统上,所有更新都将保留。
在本节中,将使用我们之前创建的目录结构来托管我们的插件和主题。然后,我们将目录挂载到我们的容器中。
docker run -d -p 80:80 -v /var/www/html/wp-content/themes,/var/www/html/wp-content/plugins,/var/www/html/wp-content/uploads myblog/wordpress:5.2
要挂载卷,我们必须使用Docker run -v标志。在下面的示例中,我们提供了容器内目标安装点的列表。当我们不包含源代码时,Docker将自动在/ var / lib目录下创建源代码目录。
docker run -d -p 80:80 \ -v themes/:/var/www/html/wp-content/themes \ -v plugins:/var/www/html/wp-content/plugins \ -v uploads/:/var/www/html/wp-content/uploads \ myblog/wordpress:5.2
让我们再次挂载卷,但是这次我们将使用之前创建的目录作为源。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c68d32e31fd2 docker_blog "docker-entrypoint.s…" 10 hours ago Up 10 hours 0.0.0.0:80->80/tcp docker_blog_1
登录WordPress的管理区域,并验证我们放在源目录中的插件和主题是否可用。现在,停止容器并再次运行。
docker run -d -p 80:80 \ -v themes/:/var/www/html/wp-content/themes \ -v plugins:/var/www/html/wp-content/plugins \ -v uploads/:/var/www/html/wp-content/uploads \ myblog/wordpress:5.2
码头工人停止c68d32
再次验证插件和主题是否可用。现在,我们已经成功地保留了对容器的更改,而无需向Docker构建中添加任何内容。
现在,我们可以自由轻松地更新我们的插件,而无需强制重建映像。我们还可以从管理门户内免费安装插件和主题,从而提供了一种更自然的使用WordPress的方法。或者,我们仍然可以将它们下载到源目录,这些目录将对运行中的容器可用。
使用非特权用户运行容器
尝试从管理门户网站安装新插件。可能会提示我们输入FTP服务器信息。 WordPress以这种方式运行的原因是因为我们安装的卷是由root用户拥有的。在www-data用户上下文下运行的WordPress没有写访问权限。我们将在下一部分中介绍解决此问题的方法。
Dockerhub提供的大量图像(包括官方WordPress图像)都以root身份运行。毫不奇怪,这不是运行容器的安全方法。容器仅应以特权级别最低的方式运行。回到上一节中写入装载的卷的问题,我们的卷作为根装载,因此由同一帐户拥有。
Docker为Dockerfiles提供了USER选项,这将使我们能够以非特权帐户运行容器。需要注意的是,用户帐户也必须存在于主机文件系统上。如果尚不存在,则必须创建它。
基本的WordPress容器运行Apache Web Server,这意味着WordPress作为www-data运行。让我们修改Dockerfile,以便我们的容器也可以作为www-data运行。
构建新版本的WordPress映像,然后重新启动容器。
请注意,容器无法加载,因为它无法将Apache绑定到端口80。只允许特权用户绑定到端口80,因此必须指示我们的容器允许非特权帐户绑定。
处理失败
重新启动容器并验证其是否成功运行。现在,我们将能够安装和更新存储在已安装卷上的插件。
在生产中运行容器
Docker撰写
--- version: '3' services: blog: build: . ports: - "80:80" volumes: - "./wp-content/:/var/www/html/wp-content:Z"
docker-compose up -d
docker-compose ps
Name Command State Ports --------------------------------------------------------------------------- docker_blog_1 docker-entrypoint.sh apach ... Up 0.0.0.0:80->80/tcp
docker-compose stop
docker-compose build
最低特权
面对现实吧,没有什么可以阻止失败。容器很有可能因某种原因而失败,从而使网站离线。显然,这是不可取的,因为我们的使用期望正常运行时间只有100%。 Docker有几种重启策略,可以在运行时应用于容器。这些策略将在容器停止或者失败后尝试重新启动它。
docker-compose exec blog id
容器只能以所需的最低特权级别运行。不幸的是,在Dockerhub上找到的许多图像(例如官方WordPress图像)都在root上下文下运行。我们可以通过对docker-compose博客服务使用以下命令来验证这一点。
uid=0(root) gid=0(root) groups=0(root)
输出将显示用户ID,组ID和容器运行时所关联的组。在下面的示例中,我们可以看到WordPress容器以root身份运行。
Docker为Dockerfile提供了USER选项,该选项允许我们指定希望容器运行的用户或者uid。此处设置的任何用户也必须存在于主机服务器上。我们应该将用户映射到容器中运行的服务的用户,并针对使用Apache Web Server的WordPress映像(即www-data帐户)进行映射。在主机系统上创建用户时,将其映射到映像中使用的相同uid(33)非常重要。
useradd -r -u 33 -g 33 www-data
在主机服务器上创建www-data用户(如果尚不存在)。
FROM wordpress USER www-data ENV WORDPRESS_DB_HOST=192.168.1.2:3307 \ WORDPRESS_DB_USER=demo_blog \ WORDPRESS_DB_PASSWORD=d7FfHZsBASsqN5Y \ WORDPRESS_DB_NAME=demo_blog \ WORDPRESS_TABLE_PREFIX=wp_
虽然Docker提供了内置的秘密服务来处理敏感信息,但仅在群体模式下可用。在本教程中,我们没有介绍Docker Orchestration解决方案,但是要解决这一关注领域,我们将需要研究如何运行容器
更新Dockerfile以添加USER www-data
以指示Docker在www-data用户上下文下运行容器。
如果尝试使用最新更改重新启动容器,则会注意到该容器将无法成功启动。原因是我们现在没有特权运行,从而阻止Apache绑定到系统端口(80)。我们可以更新docker-compose.yml文件,以指示容器允许非特权端口绑定。
sysctls: - net.ipv4.ip_unprivileged_port_start=0
将以下内容添加到服务(博客)条目下的docker-compose.yml文件中。
--- version: '3' services: blog: build: . sysctls: - net.ipv4.ip_unprivileged_port_start=0 ports: - "80:80" volumes: - "./wp-content/:/var/www/html/wp-content:Z"
docker-compose.yml文件现在应类似于以下示例。
``` sh
docker-compose build && docker-compose up -d
安全处理秘密
通过docker-compose重建Docker映像,然后重新启动它。
我们已经解决了通过利用docker-compose在生产服务器上可靠地运行Docker容器的问题。但是,我们尚未向房间中的大象讲话,因为大象正在安全地处理秘密。不幸的是,使用WordPress并没有一个简单的解决方案来安全地处理数据库凭据。无论是将这些信息存储在docker-compose.yml文件中,将其存储在Dockerfile中还是在执行docker run时将其作为env变量输入,都可以轻松发现凭据。