date: 2019-05-22 20:37:57
title: php| php 微服務之旅: devops
本篇屬於 PHP 微服務之旅
系列, 此係列會持續更新, 敬請期待.
如果說 微服務應用 對比 傳統巨石應用
最大的難點在於 基礎設施
的複雜度上, 那麼本篇就是要拋磚引玉, 提供一個完整的 devops 實例, 證明一個簡單的事實:
使用 devops 後, 微服務的開發也能有 傳統巨石應用 的簡單高效.
先提前預告一下效果, 對於一個參與到項目的開發而言:
- 本地只需要安裝 git/docker, 容器啓動後, 項目所需的開發環境全都有
- 開發者除了正常編寫代碼, 項目的 CI/CD 會在代碼提交後自動觸發, 開發者完全不用分心
devops 流程一覽
- github 私有庫 / gitlab 私有部署
- 綁定 Travis CI 持續集成
- 綁定 aliyun 容器鏡像服務(cr), 設置自動構建規則
- 綁定 aliyun 容器服務swarm(cs), 設置鏡像構建後自動部署
- 綁定 aliyun 日誌服務(sls), 設置容器日誌自動投遞到日誌服務
下面詳細講解下各部分
git
類似對比 git 與 svn 這種事, 不會再出現在我的 blog 中, 有種去翻歷史塵埃的感覺, 大概比較適合 技術史
一類的文章.
記一些 git 常用的功能吧:
-
git add/commit/stash/push
這些基礎命令不熟悉的話, 估計對應的工作去/暫存區/提交區/遠程分支
這些基礎概念也不熟, 這是基礎, 自行百度補 -
git branch/checkout/merge
這些分支相關命令, 也要很熟悉 -
git tag
只是在 commit 上做了一個標記, 建議使用統一的格式 - git clone 有 2 種方式, ssh 需要配置公鑰, https 需要賬號密碼認證, 可以使用
git config --global credential.helper "store"
記住賬號密碼 - git 是分佈式的, 本地就是一個完整的倉庫(repository), 通常會添加一個遠程倉庫來完成大家的協作
- 通常這個遠程地址命名爲 origin, 可以通過
git remote add origin url-xxx
來添加 - 當然遠程分支是可以修改的
git remote set-url origin url-xxx
- 當然遠程分支可以有多個
- 比如 github 提 PR, 需要 fork 原項目, fork 的出來的項目除了有遠程分支
origin
外, 還會多一個名爲upstream
的遠程分支對應原項目 - 當然也可以添加更多, 比如
git remote set-url gitee url-xxx
, 添加一個國內的 git 庫, 速度更快
- 比如 github 提 PR, 需要 fork 原項目, fork 的出來的項目除了有遠程分支
- 通常這個遠程地址命名爲 origin, 可以通過
- 推薦使用的 git 客戶端: github desktop
-
命令行纔是最好用的
, 但是有一個場景除外,git diff
, 強調一點,自己寫的代碼, 自己一定要 review
- github 自家的, 所以提 PR 使用快捷鍵
cmd-r
就可以了, 賊爽, 推薦給堅持開源的小夥伴
-
- 開發過程中通常使用 MR(merge request), 儘量做好 自測/code-review/CI, 從而儘量不發生
revert
, 避免不了也不要慌,gitlab revert MR
體驗賊好 - 添加 alias, 爲 git 命令行操作加速
git alias 推薦:
alias gc='git checkout'
alias gb='git branch'
alias gt='git tag'
alias gs='git status'
alias gd='git diff'
alias gl="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
alias ga='git add -A'
alias gm='git merge'
alias gp='git pull'
alias gcl='git clone --progress'
# alias gp='git pull --rebase'
alias gpp='git pull;git push'
alias gco='git commit -am'
alias gca='git commit -am "update";git pull;git push'
# 打 tag 也可以很輕鬆
function gtt
set tag_name release-v(date +"%Y%m%d%H%M")
echo $tag_name | pbcopy
pwd
git pull
git push
git tag $tag_name
git push --tags
end
# 發版到測試環境
function gdt
set b_ori (git symbolic-ref --short -q HEAD)
git checkout dev
git merge $b_ori -m 'merge'
git pull
git push
git push gh dev
git checkout -
end
我使用的 fishshell, 再次瘋狂安利一波, 幾乎零配置, 比 zsh 更高效.
可供參考的教程:
- GitHub 入門與實踐
- git 常用操作腦圖
- git 簡明指南
- git tutorial
- 廖雪峯的git教程
- git 協作流程
- 版本控制入門 – 搬進 Github
- Git實戰_201703014
- 一張圖看明白Git的四個區五種狀態
- 回滾錯誤合併
- git hook 代碼檢測
git 的部分稍顯囉嗦, 後面的 docker 部分也會有點, 畢竟 git/docker 都是 基礎功
, 這是沒法迴避的部分, 後面的實施部分要簡單不少, 幾張截圖就能搞定
docker
一樣的風格, 不再贅述 docker 好在哪, 以及 docker 的一些基礎概念, 默認你已經瞭解以下基礎知識:
- docker 的基本概念: 鏡像 容器 網絡(網絡基礎/端口映射) 文件掛載 ...
-
docker
Dockerfile
docker-compose
的基礎知識和基本用法
當然, 如果團隊有 老司機
, 你會發現使用 docker 是一件如此輕鬆的事, 幾乎只是幾個命令的事兒.
假設 git 倉庫中提供了 docker-compose.yml
文件:
version: '3.1'
services:
s1: # 定義服務名稱
image: registry.cn-shanghai.aliyuncs.com/daydaygo/dev:hyperf
volumes: # 掛載代碼路徑到容器中
- ../:/data
ports: # 端口綁定, 如果需要本地個可以訪問容器中的服務
- "80:9501"
environment: # 設置環境變量
APP_ENV: dev
links: # 此服務依賴的其他服務, 按需配置
- redis
- mysql
- rabbitmq
tty: true # 設置允許進入容器 tty
那麼, 其他開發者日常只需要:
# 定義 alias, 後面省力不少
alias doc='docker-compose
doc up -d s1 # 啓動服務(就是 docker 容器), 即由上面的 docker-compose.yml 文件定義的服務
dos stop/restart/rm s1 # 服務管理
doc exec s1 fish # 進入到容器tty, 使用 fishshell(是的, 再次安利 fishshell)
看到這裏, 希望你注意到一個更加吃驚的事實:
本地除了 git/docker, 其他什麼環境都不需要配置, 容器啓動起來後, 項目所需的環境都有了!!!
綁定 aliyun 容器鏡像服務(cr)
從這一部分開始, 後面的內容都會比較輕鬆, 幾乎只是幾張截圖.
- 使用 aliyun 容器鏡像服務, 劃重點:
免費
.
- 綁定代碼源, 推薦 github/gitlab:
- 配置自動構建規則
除了默認的 tag 觸發的自動構建(這也是上面配置 git tag
alias 的原因之一), 我通常會配置 master 分支對應鏡像 tag latest, dev 分支對應鏡像 tag test, 分別部署到 測試環境/線上環境. 當然, 需要增加其他環境, 再增加一個構建規則就好了.
而我們所需要的代碼, 即 Dockerfile, 簡單得不好意思貼進來:
- 項目鏡像構建所需的 Dockerfile
# 獲取基礎鏡像
FROM registry.cn-shanghai.aliyuncs.com/daydaygo/dev:hyperf
LABEL maintainer="daydaygo <[email protected]>" version="1.0"
# 添加項目源碼
COPY . /data
# 設置環境相關配置
COPY .env.prod /data/.env
# 啓動服務
ENTRYPOINT ["php", "/data/bin/hyperf.php", "start"]
綁定 aliyun 容器服務swarm(cs)
容器服務其實也是免費的, 收費的部分其實是集羣對應的 ecs. 這裏囉嗦一些 集羣
的概念
- 集羣的邏輯概念: 一個集羣中可以有多個
應用
, 每個應用
可能由多個服務
協同, 比如上面的 docker-compose.yml 中的 s1 服務, 使用--links
依賴了mysql/redis/rabbitmq
3 個服務 - 集羣的物理概念: 一個集羣中可以有多臺 ecs, 提供相應的 cpu/內存 等計算資源, 這些 ecs 被稱之爲
節點
- 集羣其他資源: 網絡 文件掛載 配置項 ...
使用也很簡單, 新建一個集羣, 配置好 ecs, 開發測試的話推薦使用 按量付費
, 最好至少開 2 臺來體驗.
- 好了, 配置我們的第一個應用
- 使用配置文件創建
hyperf-ms: # 定義服務名稱
# 使用容器鏡像服務中的鏡像
image: 'registry-vpc.cn-shanghai.aliyuncs.com/daydaygo/hyperf-ms:latest'
mem_limit: 0
kernel_memory: 0
memswap_reservation: 0
# 容器自動重啓
restart: always
shm_size: 0
expose:
- 9501
links:
- rabbitmq
memswap_limit: 0
# aliyun 容器服務提供的特殊功能標籤
labels:
# routing: 簡單 http/https 路由, 配置服務的 端口號->域名
aliyun.routing.port_9501: ms.daydaygo.top
# scale: 應用數量
aliyun.scale: '1'
# log: 關聯 aliyun 日誌服務, 這裏投遞容器的 stdout 到日誌服務中
aliyun.log_store_stdout: stdout
aliyun.log_ttl_stdout: 30
aliyun.log.timestamp: false
aliyun.depends: rabbitmq
rabbitmq:
image: rabbitmq:3.7.8-management-alpine
hostname: myrabbitmq
ports:
- "5672:5672" # mq
- "15672:15672" # admi
- 配置觸發器, 鏡像更新後自動部署
- 也可以在容器鏡像服務中配置
關聯 aliyun 日誌服務
關於日誌服務, 我之前也囉嗦了不少, 有興趣可以去看看之前的 blog:
上面配置好 容器服務投遞日誌到 日誌服務 後, 接下來我們還有幾步工作要做:
- 自動創建好的 日誌 project, 先修改一下備註
- 對應的 logstore
- 修改 logtail 配置, 推薦使用 json 解析, 幾乎零配置
- json 解析, 需要日誌輸出爲 json 格式, 這個也簡單, 以 PHPer 使用的
monolog
爲例, 只用配置一下 Formatter 就好了:
$app_env = env('APP_ENV', 'dev');
if ($app_env == 'dev') {
$formatter = [
'class' => \Monolog\Formatter\LineFormatter::class,
'constructor' => [
'format' => "||%datetime%||%channel%||%level_name%||%message%||%context%||%extra%\n",
'allowInlineLineBreaks' => true,
'includeStacktraces' => true,
],
];
} else {
$formatter = [
// 看這裏
'class' => \Monolog\Formatter\JsonFormatter::class,
'constructor' => [],
];
}
return [
'default' => [
'handler' => [
'class' => \Monolog\Handler\StreamHandler::class,
'constructor' => [
'stream' => 'php://stdout',
'level' => \Monolog\Logger::INFO,
],
],
'formatter' => $formatter,
],
];
- 配置好索引
- 日誌服務更多配置
- 保存快查
- 配置儀表盤 訂閱儀表盤的日報
- 配置告警 推薦告警到釘釘
一言以蔽之: 日誌服務真的是個
寶藏男孩
呀
綁定 Travis CI
CI 的根本在於: 你得有自動化測試才行
PHPer 推薦使用 phpunit, 尤其是微服務化了以後, 服務通常以接口的形式提供
, 單測簡直不要太好用
說回正題, 來看 Travis CI, 項目中添加一個 .travis.yml
的事兒:
branches:
only:
- master
- dev
language: php
services:
- docker
before_install:
- docker login registry.cn-shanghai.aliyuncs.com -u xxx -p xxx
- docker build -t ci .
- docker run -d --name ci ci
- sleep 5
script:
- docker exec ci /bin/sh -c "cd /data; phpunit"
notifications:
email:
- [email protected]
webhooks:
- https://oapi.dingtalk.com/robot/send?access_token=xxx
看配置項估計也能看明白:
- 配置分支觸發
- 根據項目下的 Dockerfile 構建鏡像
- 使用鏡像運行容器
- 執行容器中的 phpunit
- 通過 email/釘釘 通知 CI 構建信息
寫在最後
內容看起來很多, 對參與開發的人而言, 其實很省心:
本地除了安裝 git/docker 外, 並不需要其他環境; 除了寫代碼外, 不需要分心 CI/CD
最後再安利一下使用到的一些工具:
- git / github / github desktop / gitlab
- docker / docker-compose
- fishshell
- aliyun: 容器鏡像服務(cr) 容器服務swarm(cs) 日誌服務(sls)
- 釘釘: 使用釘釘機器人來蒐集消息, 當做消息box使用, 上面的所有流程, 都可以配置消息到釘釘