如何使用Docker来创建一个Dockerize的PHP应用程序

285 阅读10分钟

在本教程中,你将学习什么是Docker,以及如何使用它来创建一个Dockerize的PHP应用程序以方便部署。你将学习如何使用持续集成和部署(CI/CD)来构建和部署Heroku上的镜像。

Dockerize你的PHP应用程序是有益的,因为:

  • 容器是可移植的,可以在任何地方即时部署
  • 容器为开发者带来了统一、精简的工作环境,可以轻松共享
  • 容器是使用Docker Swarm或Kubernetes以高可用性运行你的应用程序的第一步

读完本教程后,你会知道什么是Docker以及它是如何工作的。你将了解到Docker与PHP结合的来龙去脉,以及如何使用持续集成和交付来测试你的应用程序,建立一个容器并部署它。

具体来说,你将学会如何:

  • 安装Docker
  • 运行Docker镜像
  • 构建客户镜像来运行程序
  • 使用Docker Compose建立一个开发环境
  • 在Heroku中运行我们的应用程序
  • 使用持续集成(CI)测试我们的应用程序
  • 持续部署(CD)来部署我们的应用程序

为了练习,我们将从一个演示应用程序开始,它与UnsplashAPI互动,搜索照片。这个应用是用Laravel构建的。

让我们开始吧:

TomFern / semaphore-demo-php-unsplash

  • 在你的机器上克隆该仓库,打开终端并输入:
$ git clone YOUR_REPOSITORY_URL
$ cd semaphore-demo-php-unsplash

运行演示程序

要在你的机器上运行该应用程序,你将需要

  • PHP 7
  • composer软件包管理器。
  • 一个Unsplash API密钥。

获得API密钥很容易:

  1. 注册到Unsplash
  2. 转到应用程序
  3. 选择新的应用程序
  4. 审查并接受使用条款
  5. 为应用程序设置一个名称
  6. 复制显示的访问密钥秘密密钥

在Unsplash中创建一个应用API

  1. 准备好应用程序的环境并安装依赖。
$ cd src
$ composer install
$ cp .env.example .env
$ cp .env.example.unsplash .env-unsplash
$ php artisan key:generate

你需要导入Unplash密钥作为环境变量:

  • 编辑.env-unsplash 文件。
  • 在变量旁边键入访问和秘密密钥。
export UNSPLASH_ACCESS_KEY="YOUR ACCCESS KEY"
export UNSPLASH_SECRET_KEY="YOUR SECRET KEY"
  • 源文件并启动应用程序:
$ source .env-unsplash
$ php artisan serve

http://127.0.0.1:8000,打开你的浏览器并试运行。

应用程序演示

什么是Docker?

大多数开发者使用(W|L|M)AMP堆栈作为起点,但这个环境很快就会变得不堪重负。一旦你开始感到这种痛苦,你就会开始使用一个虚拟环境来轻松地分享和复制。

Docker为我们提供了容器,它具有我们需要的所有虚拟化功能,同时也比传统的虚拟机更轻。

先决条件

Docker可以安装在大多数平台上。你可以从二进制可执行文件中安装它,或者使用官方安装程序。

安装Docker

Docker桌面

如果你使用的是最新版本的Windows或Mac,安装Docker Desktop就可以了。

如果你是一个Linux用户,Docker包很流行,通常包含在你的发行版仓库里。例如,在Ubuntu或Debian上安装它就很简单。

$ apt-get update && apt-get install docker

Docker图像

Docker是基于构建包含应用程序所需软件和配置的镜像的概念。我们还可以构建可分发的镜像,其中包含预配置的软件,如Apache服务器、缓存服务器、MySQL数据库等。我们可以在Docker Hub上分享我们的最终镜像,使每个人都能访问。

使用Docker镜像

我们可以通过运行docker images 命令来列出我们机器上的可用镜像:

$ docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu                     14.04               91e54dfb1179        5 months ago        188.4 MB
nimmis/apache-php7         latest              bdd370e4f83b        6 months ago        484.4 MB
eboraas/apache-php         latest              0501b3fdd0c2        6 months ago        367 MB
mysql                      latest              a128139aadf2        6 months ago        283.8 MB
ubuntu                     latest              d2a0ecffe6fa        7 months ago        188.4 MB
eboraas/laravel            latest              407e2d00b528        12 months ago       404.5 MB

要浏览可用的镜像,我们可以访问Docker Hub并运行docker pull <image> ,将其下载到主机上。

Docker容器

我们可以把Docker镜像比作一个类定义。我们定义它的属性和行为。容器是由这个类创建的实例。我们可以创建同一个镜像的多个实例。docker ps 命令会打印出机器上运行的容器列表。我们现在没有任何容器,所以让我们创建一个新的。

$ docker run -d php:7.4-apache
c6fbefcd630a2f4c970792af0302d9c25fe9118cec85091b04e75e7c942f5686

我们从php:7-apache镜像中创建了一个新的容器,并使用-d 标志在后台运行该作业。输出的哈希值是我们的容器ID,我们可以用它来访问这个容器,并对它进行操作。

$ docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
c6fbefcd630a        php:7.4-apache      "docker-php-entrypoi…"   39 seconds ago      Up 38 seconds       80/tcp              laughing_lalande

我们可以从输出中看到,该容器有一个ID和一个名字。让我们重新创建另一个容器并为其命名:

$ docker run -tid --name="apache_server" php:7.4-apache
fdae121b23e13690fedaab4636311d8ab6b35f32fa4c68e1c98726578de35a66

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
fdae121b23e1        php:7.4-apache      "docker-php-entrypoi…"   16 seconds ago       Up 15 seconds       80/tcp              apache_server
c6fbefcd630a        php:7.4-apache      "docker-php-entrypoi…"   About a minute ago   Up About a minute   80/tcp              laughing_lalande

容器实例几乎是即时创建的,你不会注意到任何延迟。

现在我们可以通过执行bash 命令来访问我们的容器,并将其附加到我们的终端:

$ docker exec -it apache_server bash

(you're now running a session inside the container)
$ /etc/init.d/apache2 status
[ ok ] apache2 is running.

为了避免我们的计算机被未使用的容器污染,请确保删除旧的容器:

# Delete container using ID or name
docker rm -f <container-id-or-name>

# Delete all available containers
docker rm -f $(docker ps -aq)

由于我们的容器是一个Apache服务器,所以有一种方法可以通过浏览器访问它是有意义的。当创建一个镜像时,我们需要确保通过一个特定的端口来暴露它 我们将在Dockerfiles部分更详细地介绍这个:

$ docker run -tid \
        -p 8000:80 \
        --name apache_server \
        php:7.4-apache

我们可以用docker inspect 来获得我们容器的IP:

$ docker inspect \
   -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
   CONTAINER_ID_OR_NAME

172.19.0.2

最后一部分是映射Apache服务器来运行我们的应用程序,而不是默认的Apache主页。这意味着我们需要保持我们的应用程序文件夹与服务器根文件夹的同步 (/var/www/html)。我们可以使用-v 选项来做到这一点。你可以在Docker文档中阅读更多关于容器卷的内容:

$ docker run -tid \
     -p 8000:80 \
     --name apache_server \
     -v YOUR_HOST_WWW_ROOT:/var/www/html \
     php:7.4-apache

看一下Docker Hub上的镜像描述,并阅读有关从镜像中创建容器的正确说明,总是一个好主意。

使用Docker文件

我们之前提到,每个人都可以制作一个Docker镜像并在Docker Hub上分享,而Dockerfiles是实现这一目的的主要工具。我们将看看如何配置我们自己的镜像,使其符合我们的需要。你可以查看文档中的可用命令列表。

改变一个目录到版本库根目录:

$ cd .. 

php:7.4-apache 镜像将Apache的公共目录设置为/var/www/html. 然而, 在这种情况下, 按照Laravel的惯例, 我们需要将其设置为/var/www/public. 实现这一目标的方法之一是设置一个虚拟主机配置.创建一个名为000-default.conf 的文件, 内容如下:

# 000-default.conf

<VirtualHost *:80>
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/public

  <Directory /var/www>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>

Apache, 默认情况下, 监听端口为80 (HTTP), 这在你的机器上运行服务器时不是问题.但有些云计算供应商要求容器使用不同的端口。

我们将创建一个脚本,在容器启动时动态地覆盖Apache的端口。创建一个名为start-apache 的文件,内容如下:

#!/usr/bin/env bash
sed -i "s/Listen 80/Listen ${PORT:-80}/g" /etc/apache2/ports.conf
sed -i "s/:80/:${PORT:-80}/g" /etc/apache2/sites-enabled/*
apache2-foreground

并确保该文件是可执行的:

$ chmod 755 start-apache

我们已经准备好创建一个生产就绪的镜像了。创建一个名为Dockerfile 的文件。

我们将使用FROM 子句来使用正式的php apache图像作为起点:

# Dockerfile
FROM php:7.4-apache

现在, 我们需要COPY 该文件到图像中:

...

COPY 000-default.conf /etc/apache2/sites-available/000-default.conf

...

Laravel需要启用Apache的mod_rewrite插件, 我们可以使用a2enmod 工具来完成.通过RUN ,我们在容器内运行命令:

...

RUN a2enmod rewrite

...

为了获得容器内的源文件, 我们可以再次使用COPY 命令:

...

COPY src /var/www/
RUN chown -R www-data:www-data /var/www

...

我们需要做的最后一件事是在后台运行Apache服务器。CMD 命令在一个Docker文件中只能使用一次,它需要有以下形式:

CMD ["executable","param1","param2"]

我们将调用我们先前创建的启动脚本:

...

CMD ["start-apache"]

最终的Docker文件应该是这样的:

FROM php:7.4-apache

COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
COPY start-apache /usr/local/bin
RUN a2enmod rewrite

# Copy application source
COPY src /var/www/
RUN chown -R www-data:www-data /var/www

CMD ["start-apache"]

有用的命令

虽然我们的镜像已经准备好了,但我们将通过一些对许多项目有用的命令。

如果我们想安装Node.js来管理我们的前端资产呢?

RUN apt-get update && \
    apt-get install nodejs

这将在我们的镜像中安装Node.js和npm管理器。我们可以在同一个Docker文件中多次使用RUN 命令,因为Docker为我们的镜像创建保留了历史记录。每条RUN 命令都会作为一个提交保存在版本历史中。

另一个有用的命令是ENV 。它让我们在构建过程中设置一个环境变量,并且在创建容器时也会出现。请务必查看文档中支持的命令的完整列表:

ENV MYSQL_ROOT_PASSWORD=root
ENV MYSQL_ROOT_USER=root

构建镜像

如果你以前拉过基础镜像,它将从你的电脑上加载,而不是再次下载。这意味着构建过程不会花费太多的时间。

我们的文件夹包含一个Dockerfile ,一个000-default.confstart-apachedocker build 命令将在当前目录内构建Dockerfile :

$ docker build .

如果我们现在列出我们的Docker镜像,我们会看到我们新构建的镜像:

$ docker images
REPOSITORY                                                             TAG                                    IMAGE ID            CREATED             SIZE
<none>                                                                 <none>                                 19c684978566        20 seconds ago      451MB
php                                                                    7.4-apache                             0c37fe4343a5        2 weeks ago         414MB

目前,我们的镜像还没有名字,-t 选项让我们指定了镜像的存储库和标签。

让我们给这个镜像加上一个合适的名字。语法是:

$ docker tag SOURCE_IMAGE:TAG TARGET_IMAGE:TAG

对于我们刚刚建立的镜像,我们可以使用:

$ docker tag 19c684978566 YOUR_DOCKERHUB_USER/semaphore-demo-php-unsplash

使用Docker Hub的用户名是可选的。我们只有在把镜像推送到注册中心时才需要使用它。既然我们接下来要这么做,我们不妨现在就给镜像贴上最终的名字。

我们的图像现在已经被贴上了标签。

$ docker images
REPOSITORY                                                             TAG                                    IMAGE ID            CREATED             SIZE
tomfern/semaphore-demo-php-unsplash                                    latest                                 19c684978566        3 minutes ago       451MBMB

最后一步是将其推送到Docker Hub。这一步是可选的,但如果我们打算分享镜像并帮助他人开发环境,这一步还是很有用的。

$ docker login
$ docker push YOUR_DOCKERHUB_USER/semaphore-demo-php-unsplash
  • 登录我们的Docker Hub账户后,你应该在资源库中看到新的镜像。

Docker Hub图像

Docker Compose

使用终端和记忆命令对于创建应用容器和快速上手来说并不太实用。Docker Compose使用YAML文件来配置和运行容器。这意味着我们可以将我们的应用程序Dockerfile用来构建环境,并使用docker-compose.yml 来运行容器。

第一步是在我们的机器上安装Docker Composer。在进行下面的步骤之前,请遵循Docker文档中的指示。

我们将使用docker-compose 来运行容器内的应用程序。这将加快开发速度,因为我们无需安装或配置Apache服务器就可以建立工作环境。

我们将把源代码文件映射到容器的www-root,这样我们就不必在编码时重建Docker镜像。

创建docker-compose.yml ,内容如下:

# docker-compose.yml
version: "3.9"
services:
  webapp:
    build:
      context: .
      dockerfile: ./Dockerfile.development

...

这将使用一个不同的、仅供开发的Docker文件来构建我们的镜像,该文件名为Dockerfile.development 。如果你已经在本地或Docker Hub上构建了你的镜像,你可以使用image 属性代替:

# docker-compose.yml
version: "3.9"
services:
  webapp:
    image: YOUR_DOCKERHUB_USER/semaphore-demo-php-unsplash

webapp 服务中,我们将指定暴露的端口、卷,以及可选的一些环境变量:

...

 ports:
      - "8000:80"
    volumes:
      - ./src:/var/www
    environment:
      - APP_KEY=SomeRandomStringToAddSecurity123
      - APP_ENV=development
      - APP_DEBUG=true
      - APACHE_RUN_USER=apache-www-volume
      - APACHE_RUN_GROUP=apache-www-volume
      - UNSPLASH_ACCESS_KEY=${UNSPLASH_ACCESS_KEY}
      - UNSPLASH_SECRET_KEY=${UNSPLASH_SECRET_KEY}

最终的docker-compose.yml ,看起来像这样:

version: "3.9"
services:
  webapp:
    build:
      context: .
      dockerfile: ./Dockerfile.development
    ports:
      - "8000:80"
    volumes:
      - ./src:/var/www
    environment:
      - APP_KEY=SomeRandomStringToAddSecurity123
      - APP_ENV=development
      - APP_DEBUG=true
      - APACHE_RUN_USER=apache-www-volume
      - APACHE_RUN_GROUP=apache-www-volume
      - UNSPLASH_ACCESS_KEY=${UNSPLASH_ACCESS_KEY}
      - UNSPLASH_SECRET_KEY=${UNSPLASH_SECRET_KEY}

除了Laravel和Apache的变量之外,我们还要从环境变量中设置Unsplash访问密钥的,这样我们的应用程序就会以正确的API令牌启动。

创建一个名为Dockerfile.development 的新文件:

# Dockerfile.development
FROM php:7.4-apache

# Setup Apache2 config
COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
RUN a2enmod rewrite

CMD ["apache2-foreground"]

主要区别在于,Apache是以与你自己的用户和组ID相同的方式启动的--除非权限匹配,否则应用程序不会运行。

现在,我们可以运行docker-composer up 来创建我们的容器:

$ source .env-unsplash
$ docker compose up --build

Starting semaphore-demo-php-unsplash_webapp_1 ... done
Attaching to semaphore-demo-php-unsplash_webapp_1
webapp_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
webapp_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.19.0.2. Set the 'ServerName' directive globally to suppress this message
webapp_1  | [Fri Jan 17 13:38:04.382337 2020] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.1 configured -- resuming normal operations
webapp_1  | [Fri Jan 17 13:38:04.382375 2020] [core:notice] [pid 1] AH00094: Command line: 'apache2 -DFOREGROUND'

该命令将把容器的输出附加到终端,我们将需要按ctrl+c 来退出。我们可以通过使用-d 选项来避免这种情况(docker-composer up -d)。如果我们有多个服务,我们可以指定哪一个(docker-composer up server)。

$ docker ps -a

CONTAINER ID        IMAGE                                COMMAND                  CREATED             STATUS              PORTS                           NAMES
7ec590488723        semaphore-demo-php-unsplash_webapp   "docker-php-entrypoi…"   45 minutes ago      Up 27 minutes       443/tcp, 0.0.0.0:8000->80/tcp   semaphore-demo-php-unsplash_webapp_1

使用docker-compose stop|rm 来管理你的容器。

最后,将所有的新文件添加到你的存储库中:

$ git add docker-compose.yml 000-default.conf Dockerfile* start-apache
$ git commit -m "add docker and apache config"
$ git push origin master

在Heroku中使用Docker

Heroku是一个托管平台,可以直接运行我们的Docker镜像。请查看文档中的说明。

要开始了:

  1. Heroku注册。
  2. 点击你的账户画像,然后点击账户
  3. 向下滚动,直到API密钥部分。请求一个API密钥并复制其值。我们以后会需要它。

  1. 创建一个新的应用程序,记住它的名字以便以后使用。
  2. 在你的机器上安装Heroku CLI并登录。这将打开一个浏览器窗口让你登录。
$ heroku login
$ heroku container:login
  1. Heroku有自己的Docker注册表。我们必须使用你的应用程序名称来标记和推送镜像。
$ docker tag YOUR_DOCKERHUB_USERNAME/semaphore-demo-php-unsplash registry.heroku.com/YOUR_HEROKU_APP_NAME/web
$ docker push registry.heroku.com/YOUR_HEROKU_APP_NAME/web  
  1. 设置应用程序的环境变量。APP_KEY应该是一个随机的32个字符的字符串。
$ heroku config:set UNSPLASH_ACCESS_KEY=YOUR_UNSPLASH_ACCESS_KEY
$ heroku config:set UNSPLASH_SECRET_KEY=YOUR_UNSPLASH_SECRET_KEY
$ heroku config:set APP_ENV=production
$ heroku config:set APP_KEY=SomeRandomStringToAddSecurity123
  1. 最后,启用一些Docker优化并发布应用程序。
$ heroku labs:enable --app=YOUR_HEROKU_APP_NAME runtime-new-layer-extract
$ heroku stack:set container --app YOUR_HEROKU_APP_NAME
$ heroku container:release web --app YOUR_HEROKU_APP_NAME

The application should now be up and running at: http://YOUR\_HERKOU\_APP\_NAME.herokuapp.com

Dockerizing a PHP Application

使用Semaphore进行持续集成

到此为止,我们一直在不停地抛出命令,安装东西,并尝试东西。当然,我们也犯了一些错误,不得不回去再试一次--这没什么,这是学习的唯一途径。

迟早有一天,我们会想以一种一致的方式产生结果,我们会欣赏任何帮助我们自动测试和部署的工具和做法。

在本节中,我们将学习如何创建一个CI/CD管道,使所有过程自动化。

持续集成 (CI)是在每次更新时测试应用程序的做法,因此一旦我们引入一个错误,我们就会知道它。Semaphore使我们能够很容易地持续集成我们的代码:

  1. 前往Semaphore,使用GitHub的注册按钮进行注册。

  2. 下一步是将您的Unsplash访问密钥加载到Semaphore。为了安全地存储敏感信息,Semaphore提供了秘密功能。当我们在Semaphore中引用一个秘密时,它就会自动解密并被提供。

  3. 在左边的导航菜单上,点击配置下面的秘密

  4. 点击创建新的秘密

  5. 如图所示创建环境变量,秘密的名称应该是unsplash-api

创建Unsplash的秘密

  1. 创建第二个秘密来存储Docker Hub的证书。

创建Docker Hub的秘密

  1. 创建第三个也是最后一个秘密,名为 "heroku",用于存储Heroku API密钥。

创建Heroky API Key的秘密

现在我们需要将GitHub仓库添加到Semaphore。

  1. 在左边的导航菜单上,点击项目旁边的+(加号)。

添加新项目

  1. 找到演示仓库,点击选择

选择你的资源库

  1. 选择 "我将使用现有配置"选项。该演示程序带有一个初始配置。
  2. 一旦我们做了修改,Semaphore就会接收任何现有的CI配置:编辑任何文件(例如README),提交并推送修改内容到版本库。
  3. 回到Semaphore,看到CI工作流程已经开始。

让我们检查一下现有的配置,了解Semaphore的工作方式:

  • 点击编辑工作流,打开工作流生成器。
  • 点击名为CI Pipeline的主灰色框。管线的主要组件是。

Semaphore的主要组件是。

  • 流水线:一个管道完成一个特定的任务,如测试和部署。管道是由从左到右执行的块组成。
  • 代理:代理是为管道提供动力的虚拟机。我们有三种机器类型可供选择。该机器运行一个优化的Ubuntu 20.04图像,并带有许多语言的构建工具。
  • 块(Blocks):块是由具有共同配置和目的的作业组成的,例如,构建或测试。当一个区块中的所有工作完成后,就可以开始下一个区块。
  • 工作:作业包含执行工作的命令。一个区块内的作业是平行运行的,每个作业都在它自己的独立环境中。

CI管道的主要目标是在一个干净的环境中测试代码。它将充当一个过滤器,防止故障进入生产。在设计CI时,我们要把那些更有可能失败或快速失败的测试放在第一位。

了解更多关于PHP测试的信息: PHP Laravel的7个持续集成工具

安装依赖性模块用composer下载PHP模块:

这项工作使用一些Semaphore的内置命令:

  • checkout:将GitHub仓库克隆到CI机器上。大多数工作都会在开始时做一个checkout。
  • cache:自动检测项目结构,store Semaphore缓存中的PHP模块。cache restore 检索文件,以避免再次下载它们。

代码分析块运行linters和代码覆盖率测试,以发现潜在的问题和风格问题。当我们在一个块中有多个作业时,我们可以把共享的设置命令放在**序言中。**序幕在每个作业之前执行。

测试块运行集成和浏览器测试。该块导入app-env的秘密,因为它是运行和测试应用程序所需要的。

Semaphore上的持续部署

我们将用两个额外的管道来扩展CI工作流程:

  • Dockerize:建立一个生产型Docker镜像。
  • 部署:将镜像部署到Heroku。

为了创建一个新的管道,我们将设置一个推广:

  1. 点击 "+添加推广"。
  2. 给推广命名:"Dockerize"

添加推广

  1. 勾选 "启用自动推广"选项。

配置推广

  1. 向右滚动并命名管道:"Docker build"。
  2. 点击新区块,将其名称改为:"Docker build"。
  3. 打开 "序言",输入以下内容。
checkout
cd src
cache restore
composer install --no-dev
cd ..
  1. 将作业的名称设为 "Build",并输入以下命令。
echo "$DOCKER_PASSWORD" | docker login  --username "$DOCKER_USERNAME" --password-stdin
echo "$DOCKER_PASSWORD" | docker login  --username "$DOCKER_USERNAME" --password-stdin
docker pull "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:latest || true
docker build --cache-from "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:latest -t "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:$SEMAPHORE_WORKFLOW_ID .
docker push "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:$SEMAPHORE_WORKFLOW_ID
  1. 打开 "秘密"部分,选择dockerhub

  1. 点击 "运行工作流",然后点击 "开始"

应用程序已被docker化

注意,我们正在用一个特殊的变量$SEMAPHORE_WORKFLOW_ID来标记我们的新图像。这个变量对每个工作流来说都是唯一的,这将帮助我们识别每个git提交和CI/CD运行所对应的图像版本。

Semaphore容器注册表

Dockerize管道使用两个来源构建应用程序镜像:PHP基础镜像和最新构建。构建完成后,生成的镜像被推送到Docker Hub,为部署做准备 现在,两个镜像都被拉动并推送到Docker Hub。这种在Docker Hub和Semaphore之间来回奔波的做法有点浪费,我们可以通过切换到Semaphore容器注册中心来优化构建工作,该中心托管着流行的基础镜像,速度更快、更方便,而且不计入Docker Hub的速率限制

要切换存储库,首先从GitHub获取最新的提交:

$ git pull origin master

将Dockerfile的全部内容替换为以下几行。 Semaphore镜像没有附带Apache,所以我们会在构建过程中添加一条命令来安装它:

FROM php:7.4-apache

COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
COPY start-apache /usr/local/bin
RUN a2enmod rewrite

COPY src /var/www/
RUN chown -R www-data:www-data /var/www

CMD ["start-apache"]

最后,将修改提交到GitHub。Dockerize管道现在应该工作得更快一些。

$ git add Dockerfile
$ git commit -m "use semaphore docker registry"
$ git push origin master

部署管道

Semaphore知道由谁来构建我们的Docker镜像,并在每次更新时都会这样做。

我们可以做得更多一键部署到Heroku怎么样?让我们添加一个部署管道:

  1. 再次按下编辑工作流程
  2. 向右滚动并使用"添加推广"。给推广命名:"部署到Heroku"
  3. 点击新的管道,将其称为:"部署到Heroku"。
  4. 选择块,让我们把它命名为:"Deploy"。
  5. 打开环境变量,将变量HEROKU_APP ,设置为你的Heroku应用程序名称。
  6. 打开Secrets,检查dockerhub,heroku, 和app-env
  7. 将工作命名为 "Deploy",并在框中输入以下命令。
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker pull "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:$SEMAPHORE_WORKFLOW_ID
docker tag "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:$SEMAPHORE_WORKFLOW_ID registry.heroku.com/$HEROKU_APP/web
heroku container:login
docker push registry.heroku.com/$HEROKU_APP/web            
heroku config:set UNSPLASH_ACCESS_KEY="$UNSPLASH_ACCESS_KEY"
heroku config:set UNSPLASH_SECRET_KEY="$UNSPLASH_SECRET_KEY"
heroku config:set APP_ENV=production
heroku config:set APP_KEY=qiRKsBnNoFwwOo77rDVJbK1N6IQyBKHf
heroku labs:enable --app=$HEROKU_APP runtime-new-layer-extract
heroku stack:set container --app $HEROKU_APP
heroku container:release web --app $HEROKU_APP

我们再添加一个块。它将设置当前的图像标签为最新的。这样,我们就会知道生产中最新的镜像是什么。

echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker pull "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:$SEMAPHORE_WORKFLOW_ID
docker tag "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:$SEMAPHORE_WORKFLOW_ID "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:latest
docker pull "$DOCKER_USERNAME"/semaphore-demo-php-unsplash:latest
  1. 添加第二个块,叫做 "最新镜像标签"。
  2. Secrets上,选择dockerhub
  3. 在工作框中输入以下命令。

  1. 单击 "运行工作流"并开始。

新的CI/CD管道将立即启动。一旦Docker镜像准备好了,点击推广按钮。而新的镜像将被部署到Heroku。

部署到Heroku

总结

在本教程中,我们学习了使用Docker的基本知识以及如何创建我们自己的Docker镜像。我们部署了一个演示应用程序到Heroku,并使用Semaphore持续部署到生产服务器上。

看看Github上的最终演示吧。如果你有任何问题或意见,请务必在下面发表,我们会尽力回答。