搭建高性能的私有 Composer 鏡像服務

  • 2019 年 10 月 10 日
  • 筆記

本文使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或重新修改使用,但需要註明來源。 署名 4.0 國際 (CC BY 4.0)

本文作者: 蘇洋

創建時間: 2019年08月23日 統計字數: 5748字 閱讀時間: 12分鐘閱讀 本文鏈接: https://soulteary.com/2019/08/23/build-a-high-performance-private-composer-image-service.html

搭建高性能的私有 Composer 鏡像服務

最近在完善一個基於 Composer 管理的開源軟體:Flarum 。

Flarum 是一款可以說是完全基於插件構成的社區系統,在需要對其頻繁修改更新的開發過程中,我們需要頻繁修改 composer 配置文件,在不斷 composer install 的情況下,較慢的依賴下載會嚴重影響開發調試效率。

你可能會說,使用有良好網路品質的伺服器進行初始化、或者使用企業商業網路高速網路通道、或者阿里雲之類的公網鏡像不就好了。然而這樣做也僅僅只能保障分鐘級別的部署安裝。並且非常不利於多人多環境部署調試。

本文將試著提出一個更簡單的解決方案,來解決這個問題。

寫在前面

提高安裝效率的手段其實並不多:

  • 購買更優質的網路頻寬、伺服器資源
  • 替換訪問速度慢的資源
  • 儘可能提高安裝過程中的快取利用率
  • 將軟體使用增量方式更新,減少傳輸數據量

考慮購買成本、開發、維護成本,一上來就購置頂級的專線、優化改進構建腳本使用快取、將程式完全打包成鏡像是不合理的,因為除了帶來巨額成本外,還會帶來一些意想不到的問題:快取內容狀態是否「健康」、快取文件一致性如何保障、程式碼資源類容器的後續管理?

所以「替換訪問速度比較慢的資源」無疑是低成本改善問題的不二之選。簡單的使用公網資源,流量幾經流轉時間花費的比較多,內容穩定性也不好保障,故搭建私有鏡像是一個比較好的解決方案。

下面就來講講私有鏡像的搭建。

軟體包安裝模式的改變

使用鏡像之前,composer 會從各種來源安裝軟體包,比如 GitHub、SVN、GitLab、Zip、tarball… 下載軟體包時的網路訪問品質是一個很難保障的事情,尤其是當我們需要同時訪問不同服務商分布在天南海北的伺服器的時候。

這個過程往往會持續幾分鐘甚至十幾分鐘,有的時候還會更多。最難過的是,如果我們需要多次部署安裝,或者在新的伺服器上進行安裝時,這個時間損耗會不斷放大,而且還不能夠保障多台伺服器安裝結果一致,因為不確定軟體包是否被完整下載。

而如果我們使用一個鏡像服務將上述從各種地方獲取的軟體包提前獲取,部署在距離我們需要安裝軟體包比較近的伺服器上,時間損耗將可以有效控制在分鐘級別以內,比如十幾秒~幾十秒。

選擇提供鏡像服務的應用

中國國外有不少開發者提供了 composer 的鏡像工具,本文將使用官方出品的工具:satis 。

相比較中國外其他社區/團隊出品的工具,這個工具更加的小巧,配合 CI 使用也非常簡單,只需要修改 json 文件就能夠完成軟體包的管理。

搭配 Nginx 使用可以實現高性能的私有包倉庫。

容器編排配置

compose 配置如下:

version: '3'    services:      # 官方沒有打 TAG,用 latest    # https://hub.docker.com/r/composer/satis/tags    composer:      image: composer/satis:latest      command: -vvv build /satis.json /wwwroot      links:        - nginx:nginx      networks:        - traefik      volumes:        - ./wwwroot:/wwwroot        - ./composer:/composer        - ./satis.json:/satis.json:ro      depends_on:        - nginx      # repo web server    nginx:      image: nginx:1.15.10-alpine      restart: always      networks:        - traefik      expose:        - 80      volumes:        - ./wwwroot:/var/www/html:ro        - ./conf:/etc/nginx/conf.d:ro        - ./logs:/var/log/nginx      labels:        - "traefik.enable=true"        - "traefik.frontend.rule=Host:composer.lab.com"        - "traefik.frontend.entryPoints=http,https"      healthcheck:        test: ["CMD-SHELL", "wget -q --spider --proxy off http://localhost || exit 1"]        interval: 5s        retries: 12    networks:    traefik:      external: true

可以看到我還是一如既往的選擇了 Traefik 作為了服務網關,提供證書掛載和服務發現,如果你還不了解 Traefik,可以查看歷史文章。

當然,如果你不希望使用 Traefik ,上面的配置中的 nginx 部分可以修改為下面這樣(安裝軟體包時使用訪問地址也要酌情修改哦):

# repo web server  nginx:    image: nginx:1.15.10-alpine    restart: always    networks:      - traefik    ports:      - 80:80    volumes:      - ./wwwroot:/var/www/html:ro      - ./conf:/etc/nginx/conf.d:ro      - ./logs:/var/log/nginx

上面配置中的 nginx.conf 配置,可以寫的佛系一些,因為本來它也就只需要提供 Web 服務而已:

server {      listen 80;        root /var/www/html;      index index.html;        access_log /var/log/nginx/access.log;      error_log /var/log/nginx/error.log;        location /favicon.ico {          access_log off;      }  }

最後,參考下面的 satis.json 文件的內容,修改其中的 「url」 和 require 欄位中的軟體包,生成屬於你的配置文件。

{      "name": "repo/dev",      "homepage": "https://composer.lab.com",      "repositories": [          {              "type": "composer",              "url": "https://mirrors.aliyun.com/composer/"          }      ],      "archive": {          "directory": "dist",          "format": "tar",          "prefix-url": "https://composer.lab.com",          "skip-dev": true      },      "require": {          "php": ">=7.1",          "flarum/approval": "^0.1.0",          "flarum/auth-facebook": "^0.1.0",          "flarum/auth-github": "^0.1.0",          "flarum/auth-twitter": "^0.1.0",          "flarum/tags": "^0.1.0",          "flarum/core": "^0.1.0-beta.9",          "predis/predis": "^1.1",          "league/oauth2-client": "^2.4.1",          "ramsey/uuid": "^3.5.2",          "league/flysystem": "^1.0.32"      },      "require-dependencies": true,      "require-dev-dependencies": true  }

接著使用 docker-compose up 啟動服務,等待軟體包被快取完畢就可以正式使用了。

如果你的請求量很高,可以使用 docker-compose scale nginx=4 水平擴展幾個實例,達到極高性能的需求:

WARNING: The scale command is deprecated. Use the up command with the --scale flag instead.  Starting runner-prod-composer_nginx_1 ... done  Creating runner-prod-composer_nginx_2 ... done  ...

如果你不滿足只鏡像你的項目依賴的包,希望進行全網全量軟體包鏡像,可以刪除配置文件中的 require 欄位。

{      "name": "repo/dev",      "homepage": "https://composer.lab.com",      "repositories": [          {              "type": "composer",              "url": "https://mirrors.aliyun.com/composer/"          }      ],      "archive": {          "directory": "dist",          "format": "tar",          "prefix-url": "https://composer.lab.com",          "skip-dev": true      },      "require-dependencies": true,      "require-dev-dependencies": true  }

啟動服務

使用 docker-compose up 啟動服務,第一次啟動時間會長一些,畢竟要從天南海北將軟體包進行下載,如果一切順利的話,你將看到類似下面的日誌:

Creating runner-composer_nginx_1 ... done  Creating runner-composer_composer_1 ... done  Attaching to prod-composer_nginx_1, prod-composer_composer_1  composer_1  | Scanning packages  composer_1  | The php >=7.1 requirement did not match any package  composer_1  | Creating local downloads in '/wwwroot/dist'  composer_1  | Dumping package 'phpdocumentor/reflection-docblock' in version '2.0.0'.  ...  ...  composer_1  |   - Installing phpdocumentor/reflection-docblock (4.3.1): Downloading (100%)  composer_1  | Dumping package 'phpunit/phpunit' in version '4.8.36'.  composer_1  | Dumping package 'sebastian/recursion-context' in version '1.0.0'.  composer_1  | Dumping package 'doctrine/instantiator' in version '1.2.0'.  composer_1  |   - Installing doctrine/instantiator (1.2.0): Downloading (100%)  composer_1  | Dumping package 'phpdocumentor/reflection-docblock' in version '2.0.5'.  composer_1  | wrote packages to /wwwroot/include/all$20dc965137ca8bd578a65dbc0eb7138e6dfed6bc.json  composer_1  | Writing packages.json  composer_1  | Pruning include directories  composer_1  | Writing web view  prod-composer_composer_1 exited with code 0

當然,如果你使用的是全量軟體包鏡像模式,日誌會類似下面這樣:

Creating prod-composer_nginx_1 ... done  Creating prod-composer_composer_1 ... done  Attaching to prod-composer_nginx_1, prod-composer_composer_1  composer_1  | No explicit requires defined, enabling require-all  composer_1  | Scanning packages  ...  ...  prod-composer_composer_1 exited with code 0

一旦看到 exitedwithcode0,就說明軟體包鏡像完成,可以正式使用了。

使用私有鏡像

如果你已經按照上文進行的配置,訪問你定義的私有鏡像倉庫地址: https://composer.lab.com,你會看到類似下面的介面。

實際使用起來,還是很簡單的,只需要在項目的 composer.jsonrepositories 欄位中添加:

{  ...      "repositories": [          {              "type": "composer",              "url": "https://composer.lab.com",              "options": {                  "ssl": {                      "verify_peer": false,                      "verify_peer_name": false,                      "allow_self_signed": true                  }              }          },          {              "packagist.org": false          }      ]  }

上面的配置禁用了來自公網官方倉庫的軟體包獲取,允許使用標準CA證書和自簽名證書。

最後執行 composer install 進行軟體包下載&安裝即可。

最後

下一篇文章聊聊如何搭配 CI 系統,使用 composer

—EOF