從零構建一個基於Docker的Laravel應用

Sun_翁航發表於2019-03-03

Docker簡介

其實在這樣的一個雲端計算時代, Docker 早就已被人眾所周知了,它改變了傳統物理機的虛擬化方式,使得機器的資源得到了高效的利用. 因為執行在 Docker 中的應用實際上就是執行在宿主機上的, 所以它是不需要進行硬體層面的虛擬化以及執行一個完整作業系統來支援. 於是在應用程式碼的執行效率, 記憶體的使用以及檔案的讀取速度都比傳統虛擬化的方式來的強. 而且它的啟動速度非常快,往往都是在毫秒級的,可以大大的節約了開發測試以及部署的時間. 其實對於開發人員來說, Docker 一個更大的意義就是可以保證擁有一致的執行環境, 程式設計師最常見的就是在開發測試部署環境不一致的情況下, 經常會觸發一些莫名奇妙的BUG, 為了杜絕「這段程式碼在我機器上沒問題啊」這類的問題,這也是我們要去學習 Docker 的理由之一.

如何學習 Docker?

網上充斥著大量的關於 Docker 各個方面的教程和資料, 而且由於 Docker 的飛速發展, 很多教程其實都過時了, 對於初學者來說很難去分辨把握, 隨之而來的就是一系列的坑與問題, 漸漸的磨滅了學習者的動力. 其實學習一門新技術最好的永遠都是從官方的文件入手, 然後就是 GitHub 上面一個技術人員的學習筆記, 最重要的是要去摸索實踐, 並且做好學習筆記. 其實學習一門新技術, 如果有正確的學習方法是可以少走很多彎路的, 這個有機會會寫一篇心得.

快速入門

這裡限制於篇幅和作者水平, 不會大談 Docker 底層原理以及技術實現,也不會教你如何寫一個繁瑣的 Dockerfile, 而是會從一個普通開發者的身份入手, 帶你從零搭建一個基於 Docker 的 Laravel 應用.我們的系統環境使用的是 Ubuntu17.04, 其他系統也差不多,當然 Window 的話可能就要另當別論了.

安裝Docker

在 Ubuntu 下 Docker 的安裝和常規的軟體一樣,但是由於中國特色,還有有很多要注意的點,待會會詳細說明. Docker 的安裝方式有很多種,這裡建議使用官方的一鍵安裝指令碼來,避免一系列繁瑣的操作。

1. 下載安裝

  curl -fsSL get.docker.com -o get-docker.sh
複製程式碼

然後安裝,並且選擇從阿里映象源下載:

sudo sh get-docker.sh --mirror Aliyun
複製程式碼

2. 基本配置

其實安裝後基本上就可以使用了,主要是配置一些映象源和使用者組。配置映象源的目的不多說,使用者組主要是為了再使用的時候不用使用超級管理員許可權即可執行。

  • 加入使用者組
sudo usermod -aG docker $USER
複製程式碼

PS. 配置使用者組後,可能還是會出現還是提示沒有許可權的情況,這時重啟機器即可

  • 配置映象源
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://be62qq2e.mirror.aliyuncs.com"]
}
EOF
複製程式碼

PS. 這裡的映象源是我自己阿里雲的,同學們可以自行去阿里雲獲取專有映象源地址

  • 重啟
sudo systemctl daemon-reload
sudo systemctl restart docker
複製程式碼

3. 安裝docker-compose

docker-compose類似一個包管理工具,方便我們管理映象。

curl -L https://github.com/docker/compose/releases/download/1.17.1/run.sh > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
複製程式碼

基本概念

Docker 有兩個很重要的基本概念就是映象和容器. 這兩個其實就類似物件導向中的類和例項. 映象構建起來後就是容器,然後容器可以啟動停止,對於執行於容器中的應用在執行過程中產生的資料,實際上是可以保留下來的,只要不銷燬容器. 如果銷燬或者重新構建容器後資料自然就不存在了,所以官方建議用掛載的方式來持久化, 接下來會說到.

docker-compose

docker-compose 可以說是真正的讓 Docker 現代化了. 它就類似於 PHP 的 Composer 包管理工具一樣, 是用來管理多個映象的. 它極大的降低了學習 Docker 的難度. 我們在日常的開發中, 經常會碰到需要多個容器相互配合來完成某項任務的情況,比如 Web 容器和資料庫容器之間的通訊,我們可以單獨的把一個專案中需要的所有容器和配置寫到一個 docker-compose.yml 檔案中,來統一管理.來看一下一個簡單的配置檔案格式:

version: '3'
services:
  nginx:
    build: .
    ports:
     - "80:80"

  redis:
    image: "redis:alpine"
複製程式碼

一個專案可以由多個服務(容器)工程,而 docker-compose 是面向專案進行管理.

檔案系統和網路

這是 Docker 比較複雜的一塊,簡單介紹一下. Docker 裡面的檔案系統其實很真實宿主機的一樣, 可以用同樣的命令去操作, 只是要注意的一點就是我們在容器中執行的應用配置檔案的路徑全部都是基於 Docker 的,不是基於宿主機的,很多檔案不存在的問題都是這個引起來的.比如我們在執行一個 Nginx 容器和 PHP-FPM 容器的時候,不僅要把宿主機的專案路徑對映到 Nginx 容器中,還要對映到 PHP-FPM 容器中,否則就會是一系列的 File not found. Docker 中的網路是有多種模式的, 在預設情況下是會建立一個虛擬網橋的, 實際上是 Linux 的一個 bridge,它會在掛載到它的網口之間進行轉發。並且會隨機分配一個本地未被使用的屬於 172.17.0.0/16 網段的 IP 到各個容器中.這是一個網路拓撲圖:

部署 Laravel 應用

基本介紹後我們會通過一個簡單的例項來加深理解, 就是部署一個 Laravel 應用. Web 伺服器我們會使用 Nginx, 並且通過 PHP-FPM 來處理動態請求,用 MySQL 來儲存資料, Redis 作為我們的快取和佇列驅動. 不同於網上的通過 Supervisor 來把所有服務執行在同一個容器中,我們會把這四個服務執行在四個容器中,這也是官方推薦的一種做法,然後我們會通過 docker-compose 來管理所有的服務(容器).

Nginx

直接上配置檔案:

version: '2'
services:
    nginx:
        image: nginx
        ports:
            - "8090:80"
        links:
            - php-fpm
        volumes:
          - ./nginx/www:/var/www/html
          - ./nginx/sites:/etc/nginx/sites-enabled
          - ./nginx/nginx.conf:/etc/nginx/nginx.conf
        command: [nginx-debug, '-g', 'daemon off;']
複製程式碼

其中的 services 節點下每一個表示一個服務;然後 nginx 這是個服務名可以隨便取;image 指定使用哪個映象來構建; ports 表示要暴露的埠,其中 8090 是指宿主機的埠,80 是指容器中的埠;volumes 表示掛載的目錄和檔案,我們這裡掛載了程式碼目錄,虛擬主機目錄以及配置檔案;command 表示容器啟動後要執行的命令。我們還要在當前目錄下建立一個 nginx 的目錄,用來存放一系列的檔案,還需要把配置檔案新建並且寫入配置內容(具體配置內容可以去官網檢視,這裡不說明),最後的目錄結構是這樣

Docker
    - docker-compose.yml
    - nginx
        - www
        - sites
        - nginx.conf
    
複製程式碼

可以把日誌一起掛載,這裡沒有表述出來

然後執行啟動容器的命令:

docker-compose up nginx
複製程式碼

以上不會在後臺啟動,而是會直接在當前的 shell 上,然後我們訪問應該就可以看到 Welcome to nginx!

PHP-FPM MySQL Redis

同理我們再次配置 PHP-FPM,MySQL 以及 Redis 的容器了,具體過程不多講,這裡貼出配置:

  php-fpm:
    image: 'bitnami/php-fpm:7.1'
    volumes:
      - ./nginx/www:/var/www/html
      - ./php-fpm/php.ini:/bitnami/php/conf/php.ini
    links:
      - mysql
      - redis

  mysql:
    image: mysql
    restart: always
    environment:
        MYSQL_ROOT_PASSWORD: example
    volumes:
      - /var/lib/mysql:/var/lib/mysql

  redis:
    image: redis
複製程式碼

有一點要注意的是,在配置PHP-FPM容器的時候是需要把程式碼目錄也掛載到容器裡面的,這一點很容易被遺忘,網上很多教程都沒提到,導致最後雖然按照步驟走了但就是跑不起來。其中的 links 就是配置要連線到哪個容器中。比如配置了 Nginx 容器連線到 PHP-FPM 的容器,這樣我們在 Nginx 的容器中就可以直接 ping php-fpm,在配置的時候也可以這樣 php-fpm:9000 來配置了。

配置檔案

Nginx 的配置檔案,然後還要修改一下本地的 hosts 檔案。

server {
    listen 80;
    listen [::]:80;
    root /var/www/html/laravel/public;
    index index.html index.php;
    server_name laravel-docker.app;
    location / {
            try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass php-fpm:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}
複製程式碼

執行訪問

附錄

貼一些常用的 docker-compose 命令,其中的 dc 表示 docker-compose 命令。

dc  stop            停止所有容器
dc  stop    nginx   停止指定容器
dc  up      -d      啟動容器後臺執行
dc  ps              檢視當前容器
dc  logs    kafka   檢視指定容器日誌
複製程式碼

歡迎關我的個人公眾號:左手程式碼

從零構建一個基於Docker的Laravel應用

相關文章