如何用 Docker 實現 PHP 命令行程序的 CI/CD

數人云今天帶來的文章將分享如何用Docker實現PHP命令行程序的CI/CD過程當中總體思路以及須要注意哪些問題。php

6月10日,《DevOps&SRE超越傳統運維之道》的話題將在北京延續,四位業界大牛技術齊聚,結合傳統運維現狀及實踐案例,講述DevOps&SRE的超越之道。點擊便可報名。mysql

內容要點:laravel

  • 使用Jet設置環境並在本地運行測試git

  • 配置Codeship Pro每次新代碼提交時,自動運行測試github

  • 上一步的測試經過後,自動將更新部署到服務器sql

持續集成

應用程序和測試套件已經在本地運行,下一步要作的是創建一些持續集成系統。雖然能夠設置服務器來執行此操做,但這個過程工做量略大,所以推薦一個像Codeship Pro的服務。docker

使用Jet進行本地測試

代碼提交到Codeship測試前,建議先安裝其本地版本的持續集成平臺:Jet。這會更快地推動工做,下面示例配置文件中,須要根據應用的實際狀況,作出相應調整。shell

安裝Jet後,在項目的根目錄中建立兩個新文件——數據庫

1)codeship-services.ymldocker-compose.yml文件的變種,適用於Codeship安全

2)codeship-steps.yml – 在持續集成過程當中,命令和順序的說明

codeship-services.yml文件與 docker-compose.yml幾乎同樣。內容以下:

version: "2.0"
services:
  # PHP Application
  app:
    build: .
    links:
      - database
    encrypted_env_file: .env.encrypted
    command: cron -f
  # Database
  database:
    image: mariadb
    encrypted_env_file: .env.encrypted
  # Composer
  composer:
    image: composer/composer
    volumes:
      - ./:/app

codeship-steps.yml內容以下,這個文件在例子裏很簡單,按順序執行這些的命令(一個接一個地)就好。若是應用程序容許,也能夠並列地跑某幾個步驟:

-type: serial
  steps:
  -service: composer
    command: install
  -service: app
    command: bash docker/codeship-run.sh

爲了確保應用程序容器和數據庫容器已啓動,能夠看到codeship-steps.yml文件調用了一個還沒有建立的shell腳本。若數據庫遷移,說明測試經過。把腳本放在 ./docker/codeship-run.sh ,內容以下:

#!/usr/bin/env bash
 
## Ensure that the database is up and running
function test_database {
  mysqladmin -h"$DB_HOST"-u"$DB_USERNAME"-p"$DB_PASSWORD"ping
}
 
count=0
until( test_database )
do
  ((count++))
  ## This will check up to 100 times.
  if[${count}-gt 100]
  then
    echo"Services didn't become ready in time"
    exit1
  fi
  ## And the script waits one second between each try
  sleep1
done
 
## Create the database
mysql -h"$DB_HOST"-u"$DB_USERNAME"-p"$DB_PASSWORD"-e 'CREATE DATABASE IF NOT EXISTS laravel'
 
## Run migrations
php artisan migrate
 
## Run the test suite
vendor/bin/phpunit

首先,該腳本會嘗試鏈接到數據庫。Codeship軟件會自動啓動應用程序容器和數據庫容器,但MySQL初始化須要幾秒,因此必須重試該test_database()功能,直到成功鏈接數據庫(或嘗試100次)。這在Codeship的Docker文檔中有更詳細的概述。

一旦腳本能鏈接到數據庫,它將建立默認數據庫(數據庫名爲laravel)。而後會運行遷移,經過PHPUnit建立數據庫表和測試套件。

最後,爲了測試配置正常運行和且結果經過,用Jet來運行全部步驟:

$ jet steps

若是一切正常,那麼在構建容器鏡像過程當中,會看到一堆輸出,運行返回一條成功消息:

{ContainerRunStdout=step_name:"serial_bash_docker/codeship-run.sh" service_name:"app"}: PHPUnit 5.7.19 by Sebastian Bergmann and contributors.
{ContainerRunStdout=step_name:"serial_bash_docker/codeship-run.sh" service_name:"app"}:.                                                                   1/1(100%)
 
Time:1.09 seconds, Memory:12.00MB
 
OK (1test,1 assertion)
{StepFinished=step_name:"serial_bash_docker/codeship-run.sh"type:STEP_FINISHED_TYPE_SUCCESS}
$

將倉庫鏈接到Codeship

若是還沒有提交本地代碼到GitHub或Bitbucket上。每次提交代碼更改時,Codeship都自動會從私有或公共倉庫中拉取代碼,因此只須要設置Codeship去監視那個倉庫。

在Codeship中建立一個新項目,並將其鏈接到倉庫:

image

跳出提示框時,選擇Codeship Pro作爲項目類型。

image

如今項目已經連接到Codeship。下次提交代碼時,Codeship將會編譯且使用與本地相同的codeship-steps.yml來運行。此時惟一的問題是使用本地的 .env文件,此文件不會提交到代碼倉庫,不過有個簡單方法來設置環境變量且又不會影響安全性。

加密環境變量

由於最好的作法是不要將.env文件推送到持續集成服務器,因此須要提出一種安全地將變量傳遞給Codeship方法——加密.env文件。

首先,在Codeship找到AES密鑰(一般位於項目設置的常規頁面中),並將其放在一個名爲codeship.aes的本地根目錄文件中。不要忘記將此文件添加到.gitignore,由於它是不該共享的密鑰:

image

下一步,更新codeship-services.yml文件,讓其使用加密的.env文件,而非明文.env文件:

version:"2.0"
services:
  # PHP Application
  app:
    build: .
    links:
      - database
    encrypted_env_file: .env.encrypted
    command: cron -f
  # Database
  database:
    image: mariadb
    encrypted_env_file: .env.encrypted
  # Composer
  composer:
    image: composer/composer
    volumes:
      - ./:/app

使用Jet將.env文件加密成.env.encrypted,將加密後的.env.encrypted文件提交到軟件倉庫,而後將其推送到遠程倉庫:

$ jet encrypt .env.env.encrypted
$ git add -A &&git commit -am "Adding codeship config"
$ git push origin

Codeship正在編譯代碼:

image

也能夠點擊進去,查看編譯詳細過程和每一個步驟:

image

若是上述都無誤地執行,最後會看到一個成功的編譯結果:

image

自動部署

雖然持續集成服務會讓人知道編譯和測試是否經過,但使用Codeship更大的價值在於自動化部署過程,爲了作到這一點,須要作幾件事情:

  • 在服務器上手動配置和部署代碼庫

  • 服務器上有一個SSH密鑰,容許從代碼庫拉取代碼

  • 服務器上有一個腳本,用來更新代碼並從新啓動容器

準備齊全後,就能夠構建一個部署者容器,其工做就是在編譯過程結束後,登錄到SSH服務器中,運行更新腳本。

這只是利用容器來部署代碼的一種方法,也許並非最佳的方法。另外一個選擇是使用Docker Hub等容器倉庫來編譯,而後直接從Docker Hub那裏更新容器。Docker在生產中的最佳作法仍在探索中,這種方法更適用也相對簡單。

首次手動部署代碼

此步驟根據主機服務提供商而有所不一樣,但只要服務器知足安裝了Git,Docker和Docker Compose就能夠。SSH登錄服務器:

  • 建立一個新的SSH密鑰

  • 賦予SSH密鑰能夠從代碼庫讀取訪問

  • 克隆代碼庫

  • 設置.env文件,使用一個新的APP_KEY和數據庫密碼

  • 使用docker-compose up -d –build 命令來製做鏡像,而且運行容器

如今能夠運行docker ps查看,當第一次在本地配置好這個項目時,能夠看到一樣的兩個容器在運行。

添加腳本更新服務器代碼

如今在本地版本的代碼中,添加一個shell腳本,該腳本將從倉庫中獲取更新的代碼,並重啓容器:

#!/usr/bin/env bash
 
## Pull the latest code
git pull origin master
 
## Rebuild the containers
docker-compose up -d --build
 
## Run migrations
docker exec dockerphpcliexample_app_1 php artisan migrate --force

文件名叫deploy.sh 位於docker/文件夾中。

此時,要確保文件位於服務器上,所以提交代碼到代碼庫,又將其從服務器中拉出。經過在服務器上運行命令: $ bash docker/deploy.sh ,並確保容器仍然工做。

建立一個部署者容器

綜上所述,在編譯和測試結束後,如今須要一個容器在Codeship的CI服務器遠程運行此部署腳本。在倉庫中建立一個名爲deployer/ 的新目錄,裏面包含 Dockerfile文件,.env文件和execute.sh文件。

Dockerfile:

FROM alpine:latest
 
# Install openssh
RUN apk update && apk add openssh
 
# Prep for the ssh key
RUN mkdir-p "$HOME/.ssh"
RUN touch$HOME/.ssh/id_rsa
RUN chmod600$HOME/.ssh/id_rsa
 
# Add the shell script
COPY execute.sh execute.sh
 
CMD sh execute.sh

.env:

USER=<SERVER_SSH_USERNAME>
HOST=<SERVER_HOST>
PRIVATE_SSH_KEY=<SSH_KEY (with linebreaks replaced with `\n`)>

execute.sh:

#!/usr/bin/env bash
echo-e $PRIVATE_SSH_KEY>>$HOME/.ssh/id_rsa
ssh-t -oStrictHostKeyChecking=no $USER@$HOST"cd docker-php-cli-example && sh docker/deploy.sh"

這個容器將使用.env文件中的環境變量,SSH登錄到服務器運行部署腳本。

讓Codeship Pro運行部署者容器

爲了讓Codeship知道部署者容器,把它添加到codeship-services.yml文件中:

# Deployer
  deployer:
    build: ./deployer
    encrypted_env_file: deployer/.env.encrypted

codeship-steps.yml 文件:

-service: deployer
    command: sh execute.sh

加密deployer/.env 文件,這樣能夠提交到代碼庫,而且不會暴露服務器的SSH密鑰。正如對主代碼庫那樣,用jet來加密.env文件:

$ jet encrypt deployer/.env deployer/.env.encrypted

最後,把更新的代碼推到github倉庫,確保Codeship成功地編譯和部署了代碼:

原文地址: https://blog.codeship.com/add...

活動推薦:

image
Meetup北京|DevOps&SRE超越傳統運維之道
DevOps&SRE超越傳統之道北京站來啦!6月10日,四位業界大牛技術齊聚,結合傳統運維現狀及實踐案例,講述DevOps&SRE的超越之道。

活動報名地址:
http://www.bagevent.com/event...

相關文章
相關標籤/搜索