使用Docker 部署 LNMP+Redis 環境
Docker 簡介
Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後釋出到任何流行的 Linux 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何介面。推薦核心版本3.8及以上
為什麼使用Docker
- 加速本地的開發和構建流程,容器可以在開發環境構建,然後輕鬆地提交到測試環境,並最終進入生產環境
- 能夠在讓獨立的服務或應用程式在不同的環境中得到相同的執行結果
- 建立隔離的環境來進行測試
- 高效能、超大規劃的宿主機部署
- 從頭編譯或者擴充套件現有的OpenShift或Cloud Foundry平臺來搭建自己的PaaS環境
目錄
專案原始碼地址:GitHub
安裝Docker
windows 安裝
mac
linux
# 下載安裝
curl -sSL https://get.docker.com/ | sh
# 設定開機自啟
sudo systemctl enable docker.service
sudo service docker start|restart|stop
# 安裝docker-compose
curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
目錄結構
docker_lnmp
├── v2
├── mysql
│ └── Dockerfile
│ └── my.cnf
├── nginx
│ ├── Dockerfile
│ ├── nginx.conf
│ ├── log
│ │ └── error.log
│ └── www
│ ├── index.html
│ ├── index.php
│ ├── db.php
│ └── redis.php
├── php
│ ├── Dockerfile
│ ├── www.conf
│ ├── php-fpm.conf
│ ├── php.ini
│ └── log
│ └── php-fpm.log
└── redis
└── Dockerfile
└── redis.conf
建立映象與安裝
直接使用docker-compose一鍵製作映象並啟動容器
版本一
該版本是通過拉取純淨的CentOS映象,通過Dockerfile相關命令進行原始碼編譯安裝各個服務。所以該方式很方便定製自己需要的映象,但是佔用空間大且構建慢。
git clone https://github.com/voocel/docker-lnmp.git
cd docker-lnmp
docker-compose up -d
版本二(推薦)
git clone https://github.com/voocel/docker-lnmp.git
cd docker-lnmp/v2
chmod 777 ./redis/redis.log
chmod -R 777 ./redis/data
docker-compose up -d
該版本是通過拉取官方已經制作好的各個服務的映象,再通過Dockerfile相關命令根據自身需求做相應的調整。所以該方式構建迅速使用方便,因為是基於Alpine Linux所以佔用空間很小。
測試
使用docker ps檢視容器啟動狀態,若全部正常啟動了則
通過訪問127.0.0.1、127.0.0.1/index.php、127.0.0.1/db.php、127.0.0.1/redis.php 即可完成測試
(若想使用https則請修改nginx下的dockerfile,和nginx.conf按提示去掉註釋即可,靈需要在ssl資料夾中加入自己的證照檔案,本專案自帶的是空的,需要自己替換,保持檔名一致)
進入容器內部
- 使用 docker exec
docker exec -it ngixn /bin/sh
- 使用nsenter命令
# cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;
# ./configure --without-ncurses
# make nsenter && sudo cp nsenter /usr/local/bin
為了連線到容器,你還需要找到容器的第一個程式的 PID,可以通過下面的命令獲取再執行。
PID=$(docker inspect --format "{{ .State.Pid }}" container_id)
# nsenter --target $PID --mount --uts --ipc --net --pid
PHP擴充套件安裝
- 安裝PHP官方原始碼包裡的擴充套件(如:同時安裝pdo_mysql mysqli pcntl gd四個個擴充套件)
在php的Dockerfile中加入以下命令
RUN apk add libpng-dev
&& docker-php-ext-install pdo_mysql mysqli pcntl gd
注:因為該映象缺少gd庫所需的libpng-dev包,所以需要先下載這個包
- PECL 擴充套件安裝
# 安裝擴充套件
RUN pecl install memcached-2.2.0
# 啟用擴充套件
&& docker-php-ext-enable memcached
- 通過下載擴充套件原始碼,編譯安裝的方式安裝
# 安裝Redis和swoole擴充套件
RUN cd ~
&& wget https://github.com/phpredis/phpredis/archive/4.2.0.tar.gz
&& tar -zxvf 4.2.0.tar.gz
&& mkdir -p /usr/src/php/ext
&& mv phpredis-4.2.0 /usr/src/php/ext/redis
&& docker-php-ext-install redis
&& apk add libstdc++
&& cd ~
&& wget https://github.com/swoole/swoole-src/archive/v4.2.12.tar.gz
&& tar -zxvf v4.2.12.tar.gz
&& mkdir -p /usr/src/php/ext
&& mv swoole-src-4.2.12 /usr/src/php/ext/swoole
&& docker-php-ext-install swoole
注:因為該映象需要先安裝swoole依賴的libstdc++,否則安裝成功後無法正常載入swoole擴充套件
Composer安裝
在Dockerfile中加入
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
常見問題處理
- redis啟動失敗問題
在v2版本中redis的啟動使用者為redis不是root,所以在宿主機中掛載的./redis/redis.log和./redis/data需要有寫入許可權。
chmod 777 ./redis/redis.log
chmod 777 ./redis/data
- MYSQL連線失敗問題
在v2版本中是最新的MySQL8,而該版本的密碼認證方式為Caching_sha2_password,而低版本的php和mysql視覺化工具可能不支援,可通過phpinfo裡的mysqlnd的Loaded plugins檢視是否支援該認證方式,否則需要修改為原來的認證方式mysql_native_password:
select user,host,plugin,authentication_string from mysql.user;
ALTER USER `root`@`%` IDENTIFIED WITH mysql_native_password BY `123456`;
FLUSH PRIVILEGES;
-
注意掛載目錄的許可權問題,不然容器成功啟動幾秒後立刻關閉,例:以下/data/run/mysql 目錄沒許可權的情況下就會出現剛才那種情況
docker run --name mysql57 -d -p 3306:3306 -v /data/mysql:/var/lib/mysql -v /data/logs/mysql:/var/log/mysql -v /data/run/mysql:/var/run/mysqld -e MYSQL_ROOT_PASSWORD=123456 -it centos/mysql:v5.7
-
需要注意php.ini 中的目錄對應 mysql 的配置的目錄需要掛載才能獲取檔案內容,不然php連線mysql失敗
# php.ini mysql.default_socket = /data/run/mysql/mysqld.sock mysqli.default_socket = /data/run/mysql/mysqld.sock pdo_mysql.default_socket = /data/run/mysql/mysqld.sock # mysqld.cnf pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock
-
使用php連線不上redis
# 錯誤的 $redis = new Redis; $rs = $redis->connect(`127.0.0.1`, 6379);
php連線不上,檢視錯誤日誌
PHP Fatal error: Uncaught RedisException: Redis server went away in /www/index.php:7
考慮到docker 之間的通訊應該不可以用127.0.0.1 應該使用容器裡面的ip,所以檢視redis 容器的ip
[root@localhost docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b5f7dcecff4c docker_nginx "/usr/sbin/nginx -..." 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx 60fd2df36d0e docker_php "/usr/local/php/sb..." 7 seconds ago Up 5 seconds 9000/tcp php 7c7df6f8eb91 hub.c.163.com/library/mysql:latest "docker-entrypoint..." 12 seconds ago Up 11 seconds 3306/tcp mysql a0ebd39f0f64 docker_redis "usr/local/redis/s..." 13 seconds ago Up 12 seconds 6379/tcp redis
注意測試的時候連線地址需要容器的ip或者容器名names,比如redis、mysql.
例如nginx配置php檔案解析 fastcgi_pass php:9000;
例如php連線redis $redis = new Redis;$res = $redis->connect(`redis`, 6379);因為容器ip是動態的,重啟之後就會變化,所以可以建立靜態ip
第一步:建立自定義網路
#備註:這裡選取了172.172.0.0網段,也可以指定其他任意空閒的網段 docker network create --subnet=172.171.0.0/16 docker-at docker run --name redis326 --net docker-at --ip 172.171.0.20 -d -p 6379:6379 -v /data:/data -it centos/redis:v3.2.6
連線redis 就可以配置對應的ip地址了,連線成功
$redis = new Redis; $rs = $redis->connect(`172.171.0.20`, 6379);
另外還有種可能phpredis連線不上redis,需要把redis.conf配置略作修改。
bind 127.0.0.1 改為: bind 0.0.0.0
- 啟動docker web服務時 虛擬機器埠轉發 外部無法訪問 一般出現在yum update的時候(WARNING: IPv4 forwarding is disabled. Networking will not work.)或者宿主機可以訪問,但外部無法訪問
vi /etc/sysctl.conf
或者
vi /usr/lib/sysctl.d/00-system.conf
新增如下程式碼:
net.ipv4.ip_forward=1
重啟network服務
systemctl restart network
檢視是否修改成功
sysctl net.ipv4.ip_forward
如果返回為"net.ipv4.ip_forward = 1"則表示成功了
- 如果使用最新的MySQL8無法正常連線,由於最新版本的密碼加密方式改變,導致無法遠端連線。
# 修改密碼加密方式
ALTER USER `root`@`%` IDENTIFIED WITH mysql_native_password BY `123456`;
常用命令
-
docker start
容器名(容器ID也可以) -
docker stop
容器名(容器ID也可以) -
docker run
命令加 -d 引數,docker 會將容器放到後臺執行 -
docker ps
正在執行的容器 -
docker logs
–tail 10 -tf 容器名 檢視容器的日誌檔案,加-t是加上時間戳,f是跟蹤某個容器的最新日誌而不必讀整個日誌檔案 -
docker top
容器名 檢視容器內部執行的程式 -
docker exec -d
容器名 touch /etc/new_config_file 通過後臺命令建立一個空檔案 -
docker run --restart=always --name
容器名 -d ubuntu /bin/sh -c “while true;do echo hello world; sleep 1; done” 無論退出程式碼是什麼,docker都會自動重啟容器,可以設定 –restart=on-failure:5 自動重啟的次數 -
docker inspect
容器名 對容器進行詳細的檢查,可以加 –format=`{(.State.Running)}` 來獲取指定的資訊 -
docker rm
容器ID 刪除容器,注,執行中的容器無法刪除 -
docker rm $(docker ps -aq)
刪除所有容器 -
docker rmi $(docker images -aq)
刪除所有映象 -
docker images
列出映象 -
docker pull
映象名:標籤 拉映象 -
docker search
查詢docker Hub 上公共的可用映象 -
docker build -t=`AT/web_server:v1`
命令後面可以直接加上github倉庫的要目錄下存在的Dockerfile檔案。 命令是編寫Dockerfile 之後使用的。-t選項為新映象設定了倉庫和名稱:標籤 -
docker login
登陸到Docker Hub,個人認證資訊將會儲存到$HOME/.dockercfg, -
docker commit -m="comment " --author="AT"
容器ID 映象的使用者名稱/倉庫名:標籤 不推薦這種方法,推薦dockerfile -
docker history
映象ID 深入探求映象是如何構建出來的 -
docker port
映象ID 埠 檢視對映情況的容器的ID和容器的埠號,假設查詢80埠對應的對映的埠 -
run
執行一個容器, -p 8080:80 將容器內的80埠對映到docker宿主機的某一特定埠,將容器的80埠繫結到宿主機的8080埠,另 127.0.0.1:80:80 是將容器的80埠繫結到宿主機這個IP的80埠上,-P 是將容器內的80埠對本地的宿主機公開 - http://docs.docker.com/refere… 檢視更多的命令
-
docker push
映象名 將映象推送到 Docker Hub -
docker rmi
映象名 刪除映象 -
docker attach
容器ID 進入容器 -
docker network create --subnet=172.171.0.0/16 docker-at
選取172.172.0.0網段 -
docker build
就可以加 -ip指定容器ip 172.171.0.10 了
刪除所有容器和映象的命令
docker rm `docker ps -a |awk `{print $1}` | grep [0-9a-z]` 刪除停止的容器
docker rmi $(docker images | awk `/^<none>/ { print $3 }`)
Dockerfile語法
-
MAINTAINER
標識映象的作者和聯絡方式 -
EXPOSE
可以指定多個EXPOSE向外部公開多個埠,可以幫助多個容器連結 -
FROM
指令指定一個已經存在的映象 -
#
號代表註釋 -
RUN
執行命令,會在shell 裡使用命令包裝器 /bin/sh -c 來執行。如果是在一個不支援shell 的平臺上執行或者不希望在shell 中執行,也可以 使用exec 格式 的RUN指令 -
ENV REFRESHED_AT
環境變數 這個環境亦是用來表明映象模板最後的更新時間 -
VOLUME
容器新增捲。一個卷是可以 存在於一個或多個容器內的特定的目錄,對卷的修改是立刻生效的,對卷的修改不會對更新映象產品影響,例:VOLUME[“/opt/project”,”/data”] -
ADD
將構建環境 下的檔案 和目錄複製到映象 中。例 ADD nginx.conf /conf/nginx.conf 也可以是取url 的地址檔案,如果是壓縮包,ADD命令會自動解壓、 -
USER
指定映象用那個USER 去執行 -
COPY
是複製本地檔案,而不會去做檔案提取(解壓包不會自動解壓) 例:COPY conf.d/ /etc/apache2/ 將本地conf.d目錄中的檔案複製到/etc/apache2/目錄中
docker-compose.yml 語法說明
-
image
指定為映象名稱或映象ID。如果映象不存在,Compose將嘗試從網際網路拉取這個映象 -
build
指定Dockerfile所在資料夾的路徑。Compose將會利用他自動構建這個映象,然後使用這個映象 -
command
覆蓋容器啟動後預設執行的命令 -
links
連結到其他服務容器,使用服務名稱(同時作為別名)或服務別名(SERVICE:ALIAS)都可以 -
external_links
連結到docker-compose.yml外部的容器,甚至並非是Compose管理的容器。引數格式和links類似 -
ports
暴露埠資訊。宿主機器埠:容器埠(HOST:CONTAINER)格式或者僅僅指定容器的埠(宿主機器將會隨機分配埠)都可以(注意:當使用 HOST:CONTAINER 格式來對映埠時,如果你使用的容器埠小於 60 你可能會得到錯誤得結果,因為 YAML 將會解析 xx:yy 這種數字格式為 60 進位制。所以建議採用字串格式。) -
expose
暴露埠,與posts不同的是expose只可以暴露埠而不能對映到主機,只供外部服務連線使用;僅可以指定內部埠為引數 -
volumes
設定卷掛載的路徑。可以設定宿主機路徑:容器路徑(host:container)或加上訪問模式(host:container:ro)ro就是readonly的意思,只讀模式 -
volunes_from
掛載另一個服務或容器的所有資料卷 -
environment
設定環境變數。可以屬於陣列或字典兩種格式。如果只給定變數的名稱則會自動載入它在Compose主機上的值,可以用來防止洩露不必要的資料 -
env_file
從檔案中獲取環境變數,可以為單獨的檔案路徑或列表。如果通過docker-compose -f FILE指定了模板檔案,則env_file中路徑會基於模板檔案路徑。如果有變數名稱與environment指令衝突,則以後者為準(環境變數檔案中每一行都必須有註釋,支援#開頭的註釋行) -
extends
基於已有的服務進行服務擴充套件。例如我們已經有了一個webapp服務,模板檔案為common.yml。編寫一個新的 development.yml 檔案,使用 common.yml 中的 webapp 服務進行擴充套件。後者會自動繼承common.yml中的webapp服務及相關的環境變數 -
net
設定網路模式。使用和docker client 的 –net 引數一樣的值 -
pid
和宿主機系統共享程式名稱空間,開啟該選項的容器可以相互通過程式id來訪問和操作 -
dns
配置DNS伺服器。可以是一個值,也可以是一個列表 -
cap_add,cap_drop
新增或放棄容器的Linux能力(Capability) -
dns_search
配置DNS搜尋域。可以是一個值也可以是一個列表 - 注意:使用compose對Docker容器進行編排管理時,需要編寫docker-compose.yml檔案,初次編寫時,容易遇到一些比較低階的問題,導致執行docker-compose up時先解析yml檔案的錯誤。比較常見的是yml對縮排的嚴格要求。yml檔案還行後的縮排,不允許使用tab鍵字元,只能使用空格,而空格的數量也有要求,一般兩個空格。
專案原始碼地址:GitHub