2020系統綜合實踐3 使用Docker Compose部署LNMP


項目已上傳至GitHub


1. 安裝Docker Compose

參考官方教程

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 下載安裝
# 這一步不FQ比較慢, 可以去直接github下載好拷貝到/usr/local/bin/docker-compose目錄下

sudo chmod +x /usr/local/bin/docker-compose # 應用權限

docker-compose --version # 測試是否安裝成功


2. Dockerfile編寫

考慮到樹莓派無法使用MySql,選擇了Nginx+MariaDb+PHP+Pdo

Dockerfile-php

參考官方readme

FROM php:7.4-fpm
LABEL author=qyanzh
RUN apt-get update && apt-get install -y \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    && docker-php-ext-install pdo pdo_mysql \ # 新增行,安裝pdo
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd

5/7更新
如果發現apt-get update過程很慢, 可以參考docker php-fpm 鏡像修改apt源 - 簡書

Dockerfile-nginx

只聲明了一個端口號,配置文件的掛載放在yml中進行。

FROM nginx
LABEL author=qyanzh
EXPOSE 2420 # 聲明暴露端口號2420

nginx配置文件

由於不熟悉nginx,在這一步花了很長時間,遇到了很多錯誤:

  • file not found
  • 404 Not Found
  • 502 Bad Gateway
  • 訪問網頁變成直接下載,從下面這張圖可以看出我試了多少次Orz

以上錯誤基本都是由於路徑配置不正確。

正確的配置

server {
    listen       2420;
    server_name  localhost;

    location / {
        root   /usr/share/my_web/html; # nginx容器中web文件存放目錄,和yml對應
        index  index.html index.htm;
    }

    location ~ \.php$ {
       root           /usr/share/my_web/php; # php容器中web文件存放目錄,和yml對應
       fastcgi_pass   cphp:9000; # php服務器默認端口9000,后面會解釋為什么是cphp
       fastcgi_index  index.php;
       fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
       include        fastcgi_params;
    }
}

訪問localhost時,首先nginx會根據index指定的順序依次檢查web目錄下的對應文件,如果是html文件,由nginx直接展示。如果訪問到php文件nginx會發送一個請求到cphp:9000cphp將其web目錄下對應的php文件解析為html文件后返回給nginx,再由nginx返回給瀏覽器,nginx在這里充當反向代理。(具體的原理和location匹配規則在文末的參考資料給出。)

訪問兩個頁面的響應頭:


Dockerfile-mariadb

較簡單,直接在docker-compose.yml中給出。

Dockerfile-phpmyadmin

FROM phpmyadmin/phpmyadmin
LABEL author=qyanzh
EXPOSE 8080

3. 使用Compose實現多容器運行機制

項目結構

docker-compose.yml

參考官方教程以及twang2218/docker-lnmp(強烈推薦看一看):

version: "3"
services:
  php:
    image: my-php # 鏡像名
    container_name: cphp # 容器名
    build:
      context: .
      dockerfile: Dockerfile-php # 指定自定義的Dockerfile
    environment:
      MYSQL_PASSWORD: 1234 # 方便直接在php代碼中引用
    volumes:
      - ./my_web_dir:/usr/share/my_web/php # 掛載到本機web目錄,相當於-v
    networks:
      - front_end
      - back_end

  nginx:
    image: my-nginx
    container_name: cngx
    build:
      context: .
      dockerfile: Dockerfile-nginx
    ports:
      - "80:2420" # 暴露80端口,相當於 -p 80:2420
    volumes:
      - ./my_web_dir:/usr/share/my_web/html
      - ./default.conf:/etc/nginx/conf.d/default.conf # 掛載配置文件
    networks:
      - front_end

  mariadb:
    image: mariadb
    container_name: cdb
    restart: always
    volumes:
      - mariadb-data:/bitnami/mariadb # 掛載volumn實現數據持久化
    environment:
      MYSQL_ROOT_PASSWORD: 1234
    networks:
      - back_end

  phpmyadmin:
    image: my-phpmyadmin
    container_name: cadm
    build: 
      context: .
      dockerfile: Dockerfile-phpmyadmin
    ports: 
      - "8080:80" # phpmyadmin默認監聽80
    environment:
      PMA_HOST: cdb # 指定mysql服務所在的host
    networks: 
      - back_end

volumes:
  mariadb-data:

# 自定義網絡的原因參見下方php訪問數據庫測試
networks:
  front_end:
  back_end:

通過volumn將容器目錄掛載本地,在本地的修改可以直接被容器讀取,非常方便。:前面的表示要掛載的本地目錄/文件,:后面表示對應的容器內目錄/文件。

構建運行

docker-compose down # 移除之前運行的
docker-compose up -d --build # 這也是個坑點,修改過后要加--build否則用的還是之前的鏡像


4. 服務測試

nginx+php測試

mariadb測試

mysql -h localhost -u root -p

然而報錯

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

經查是因為mariadb是運行在cdb中的,而cdb作為獨立的容器有自己的IP,所以就無法通過宿主機IPlocalhost來訪問,需要先查一下容器IP。

docker inspect cdb
mysql -h 172.20.0.2 -u root -p

php對數據庫操作測試

參考菜鳥教程的代碼,做一些必要的修改:

由於容器間互相隔離,localhost需要改掉。根據mariadb測試,應該把$host的值改為cdb的IP,但是每次容器重啟后這個IP是會變化的,就需要每次去改測試代碼。容易想到的方式是給其分配靜態IP,但這樣太不優雅了。經過查閱資料,發現位於同一網絡下的容器可以通過容器名相互訪問,為了隔離性,應把不同職責的容器分散在不同網絡中。cdbcphp同屬於back_end網絡,所以將$host的值改為容器名cdb即可。上面的nginx配置文件fastcgi_pass的取值同理。

<?php
$dbms = 'mysql';     //數據庫類型
$host = 'cdb'; //數據庫主機名,修改為容器名
$user = 'root';      //數據庫連接用戶名
$pass = $_ENV["MYSQL_PASSWORD"]; //通過yml中定義的環境變量獲得對應的密碼
$dsn = "$dbms:host=$host;"; // "mysql:host=cdb"

try {
    $dbh = new PDO($dsn, $user, $pass); //初始化一個PDO對象
    echo "連接成功<br/>";
    $dbh = null;
} catch (PDOException $e) {
    die("Error!: " . $e->getMessage() . "<br/>");
}
//默認這個不是長連接,如果需要數據庫長連接,需要最后加一個參數:array(PDO::ATTR_PERSISTENT => true) 變成這樣:
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$db->exec("create database if not exists test_db;");
$db->exec("use test_db;");
$db->exec("create table if not exists t(num integer);");
$db->exec("delete from t;");

// 增
$db->exec("insert into t(num) values(2420);");
showDb($db, "insert:\n");
// 改
$db->exec("update t set num=031702420 where num=2420;");
showDb($db, "update:\n");
// 刪
$db->exec("delete from t;");
showDb($db, "delete:\n");
// 查
function showDb($db, $op)
{
    print_r($op);
    $sql = "select * from t";
    $result = $db->query($sql);
    while ($arr = $result->fetch()) {
        print_r($arr);
    }
    echo "<br/>";
}

如果出現Connection Refused,可能是因為數據庫未啟動完畢,大約需要10秒。可以將up指令中的-d去掉來看容器的狀態(或者docker logs),直到出現:

cdb | Version: '10.4.12-MariaDB-1:10.4.12+maria~bionic'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306


5. PhpMyAdmin

參考通過Docker為MySQL安裝phpMyAdmin管理界面_運維_嘿客的技術閑筆-CSDN博客,具體已在yml中給出。

第一次沒設置PMA_HOST環境變量,導致無法訪問。錯誤信息也說明是主機名找不到,在yml中設置為cdb即可。


附錄:一鍵刪除命令

# 刪除所有容器
docker rm -f $(docker ps -aq)  
# 刪除所有鏡像
docker rmi $(docker images -q)
# 刪除所有<none>鏡像
docker rmi $(docker images | grep "none" | awk '{print $3}')

用時和體會

加上博客約14小時。做完這次實踐對Docker的理解深了不少,相比前兩次蜻蜓點水般的使用,這次更有完整項目的感覺。面對沒學過的東西,搜集資料和debug的過程是冗長且痛苦的,但這正是鍛煉自學能力的機會。


參考

php - Docker Hub

docker php-fpm 鏡像修改apt源 - 簡書

Nginx+Php-fpm運行原理詳解_運維_一路向前ylc-CSDN博客

Nginx location 匹配順序整理 - python修行路 - 博客園

Get started with Docker Compose | Docker Documentation

twang2218/docker-lnmp: Docker example of LNMP setup (Compose, Swarm)

windows下如何查看和修改MySQL的端口號

docker-compose 安裝 mariadb數據庫_運維_jiangbenchu的博客-CSDN博客

PHP 連接 MySQL | 菜鳥教程

PHP PDO | 菜鳥教程

PHP: 用戶自定義函數 - Manual

PDO 基本使用(簡)_PHP_jia_1418422386的博客-CSDN博客

docker 如何刪除none鏡像_運維_李留白-CSDN博客

phpmyadmin/phpmyadmin - Docker Hub

使用docker-compose編寫常規的lnmp容器,pdo連接mysql失敗。 - 大步向前blue - 博客園

通過Docker為MySQL安裝phpMyAdmin管理界面_運維_嘿客的技術閑筆-CSDN博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM