docker:Dockerfile構建LNMP平台
1、dockerfile介紹
Dockerfile是Docker用來構建鏡像的文本文件,包含自定義的指令和格式。可以通過docker build命令從Dockerfile中構建鏡像。這個過程與傳統分布式集群的編排配置過程相似,且提供了一系列統一的資源配置語法。用戶可以用這些統一的語法命令來根據需求進行配置,通過這份統一的配置文件,在不同的平台上進行分發,需要使用時就可以根據配置文件自動化構建,這解決了開發/運維人員構建鏡像的復雜過程。同時,Dockerfile與鏡像配合使用,使Docker在構建時可以充分利用鏡像的功能進行緩存,大大提升了Docker的使用效率。
用通俗一點的話來講:dockerfile就是根據自己的需要自定義一個鏡像,就像你寫shell腳本一樣,把一連串的過程或步驟全部寫進dockerfile文件中,一步一步的執行dockerfile文件中你寫的內容。
2、dockerfile指令
3、build命令
Usage:docker build [OPTIONS] PATH | URL | -
OPTIONS:
-t ,--tag list #構建后的鏡像名稱
-f, --file string #指定Dockerfiile文件位置
示例:
1,docker build .
2,docker build -t nginx:v10 .
3,docker build -t nginx:v10 -f /path/Dockerfile /path
一般常用第2種方式構建,我們在構建時都會切換到Dockerfile文件的目錄下進行構建,所以不需要指定-f參數。如果還不是很明白的話,下面我們來構建nginx鏡像、php鏡像來理解一下。
4、環境說明
在本文中我都是基於centos 7官方鏡像來構建、nginx和php用的源碼包來構建,如果你不想用源碼包,也可用yum方式構建:
- nginx,用的是源碼包來構建,版本為nginx-1.12.1.tar.gz,下載地址http://nginx.org/en/download.html/
- php,也用的源碼包來構建,版本為php-5.6.31.tar.gz,下載地址http://php.net/downloads.php
在來看一下目錄結構:
[root@ganbing /]# tree dockerfile/ dockerfile/ ├── nginx │ ├── Dockerfile │ ├── nginx-1.12.1.tar.gz │ └── nginx.conf └── php ├── Dockerfile ├── php-5.6.31.tar.gz └── php.ini
其中,在dockerfile目錄下創建了兩個目錄(nginx、php),里面分別存放Dockerfile文件、源碼包。nginx目錄下還放了nginx.conf配置文件,php目錄下也放置了php.ini配置文件。
有些人會問為什么要把nginx.conf、php.ini配置文件放到這里,有兩個原因,其一,把這兩個默認的配置文件放在這里可以提前修改好所需要的參數,當容器啟動后,就不需要在進入容器去修改了。當然,我這里只是練習環境,並未對這兩個文件做任何更改。其二,在實際環境中,這兩個文件是經常需要修改的,單獨拿出來后在啟動容器時你可以把這兩個文件mount到容器中,便於管理。
5、nginx構建
5.1 Dockerfile內容
FROM centos:7
MAINTAINER blog.51cto.com/ganbing
ENV TIME_ZOME Asia/Shanghai
RUN yum -y install gcc gcc-c++ make openssl-devel pcre-devel ADD nginx-1.12.1.tar.gz /tmp RUN cd /tmp/nginx-1.12.1 && \ ./configure --prefix=/usr/local/nginx && \ make -j 2 && \ make install RUN rm -rf /tmp/nginx* && yum clean all && \ echo "${TIME_ZOME}" > /etc/timezone && \ ln -sf /usr/share/zoneinfo/${TIME_ZOME} /etc/localtime COPY nginx.conf /usr/local/nginx/conf/ WORKDIR /usr/local/nginx/ EXPOSE 80 CMD ["./sbin/nginx","-g","daemon off;"]
來分析一下上面的內容,當你構建時,它會根據你編排好的內容一步一步的執行下去,如果當中的某一步執行不下去,會立刻停止構建。上面的大部分指令都很好理解,在上文中的dockerifle指令中有介紹,最后一個指令我要詳細說明一下:CMD ["./sbin/nginx","-g","daemon off;"]
- /sbin/nginx 這個沒什么說的,就是正常啟動nginx服務;
- -g: 設置配置文件外的全局指令,也就是啟動nginx時設置了daemon off參數,默認參數是打開的on,是否以守護進程的方式運行nginx,守護進程是指脫離終端並且在后台運行的進程。這里設置為off,也就是不讓它在后台運行。為什么我們啟動nginx容器時不讓它在后台運行呢,docker 容器默認會把容器內部第一個進程,也就是pid=1的程序作為docker容器是否正在運行的依據,如果docker 容器pid掛了,那么docker容器便會直接退出。
5.2 nginx.conf內容
......
省略其它默認配置
......
server {
listen 80; server_name localhost; root html; index index.html index.php; location ~ \.php$ { root html; fastcgi_pass lnmp_php:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
配置中主要添加了 location ~ .php這一段的內容,其中fastcgi_pass的 lnmp_php,這個是后面啟動php容器時的名稱。了解nginx原理的朋友應該能理解,當匹配到php的請求時,它會轉發給lnmp_php這個容器php-fpm服務來處理。正常情況下,如果php服務不是跑在容器中,lnmp_php這個內容一般寫php服務器的Ip地址。
5.3 build構建
nginx源碼包、nginx.conf、Dockerfile都准備好了之后,現在我們可以來用docker build來構建這個鏡像了:
切換到nginx目錄下:
[root@ganbing /]# cd /dockerfile/nginx/ [root@ganbing nginx]# ls Dockerfile nginx-1.12.1.tar.gz nginx.conf 構建: [root@ganbing nginx]# docker build -t nginx:1.12.1 .
5.4 查看鏡像是否構建成功
[root@ganbing /]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx 1.12.1 19b0dc5eb6bb 15 minutes ago 419MB centos 7 ff426288ea90 7 weeks ago 207MB
nginx鏡像已經構建好了,是不是還多了一個centos:7的鏡像呢,這主要是在Dockerfile文件中你的FROM指令寫的是centos:7,如果你的宿主機沒有這個鏡像,它就會從 hub.docker.co 中去pull這個鏡像。
6、php構建
6.1 Dockerfile內容
FROM centos:7
MAINTAINER blog.51cto.com/ganbing
ENV TIME_ZOME Asia/Shanghai
RUN yum install -y gcc gcc-c++ make gd-devel libxml2-devel libcurl-devel libjpeg-devel libpng-devel openssl-devel ADD php-5.6.31.tar.gz /tmp/ RUN cd /tmp/php-5.6.31 && \ ./configure --prefix=/usr/local/php \ --with-config-file-path=/usr/local/php/etc \ --with-mysql --with-mysqli \ --with-openssl --with-zlib --with-curl --with-gd \ --with-jpeg-dir --with-png-dir --with-iconv \ --enable-fpm --enable-zip --enable-mbstring && \ make -j 4 && \ make install RUN cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf && \ sed -i 's/127.0.0.1/0.0.0.0/g' /usr/local/php/etc/php-fpm.conf && \ sed -i "21a daemonize=no" /usr/local/php/etc/php-fpm.conf && \ echo "${TIME_ZOME}" > /etc/timezone && \ ln -sf /usr/share/zoneinfo/${TIME_ZOME} /etc/localtime COPY php.ini /usr/local/php/etc/ RUN rm -rf /tmp/php* && yum clean all WORKDIR /usr/local/php/ EXPOSE 9000 CMD ["./sbin/php-fpm","-c","/usr/local/php/etc/php-fpm.conf"]
上面內容和nginx的Dockerfile風格差不多,也是一步一步的來。先安裝依賴包、解壓、配置並編譯,然后修改下配置文件,啟動php-fpm服務。是不是發現寫Dockerfile挺簡單的,就是把你平時部署php服務的步驟思路寫到這個Dockerfile里面。
6.2 php.ini內容
這個內容我沒有修改,是默認的配置內容。
6.3 build構建
php源碼包、php.ini、Dockerfile都准備好了之后,現在我們可以來用docker build來構建這個鏡像了:
切換到php目錄下:
[root@ganbing /]# cd /dockerfile/php/ [root@ganbing php]# ls Dockerfile php-5.6.31.tar.gz php.ini 構建: [root@ganbing nginx]# docker build -t php:5.6.31 .
6.4 查看鏡像是否構建成功
[root@ganbing php]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE php 5.6.31 9ed5ccce1735 3 minutes ago 1GB nginx 1.12.1 19b0dc5eb6bb About an hour ago 419MB centos 7 ff426288ea90 7 weeks ago 207MB
7、運行容器
7.1 創建自定義網絡lnmp
先創建一個自定義網絡,運行ningx、php這些容器的時候加入到lnmp網絡中來:
先來查看一下默認的網絡:
[root@ganbing php]# docker network ls NETWORK ID NAME DRIVER SCOPE 8be78de1f4b8 bridge bridge local d77497b635bb host host local 637e45b21ed3 none null local 創建: [root@ganbing php]# docker network create lnmp 49fbb89c7e83e5aa817973cab0db06eea9f3090597dc29d2649d79a8c23d8304
7.2 創建php容器
創建容器:
[root@ganbing php]# docker run -itd --name lnmp_php --network lnmp --mount type=bind,src=/app/wwwroot,dst=/usr/local/nginx/html php:5.6.31 5676b229125a9372c454488a4e55e8542ca761cd682c34f061c051c511df2340
參數說明:
-itd: 在容器中打開一個偽終端進行交互操作,並在后台運行;
--name: 為容器分配一個名字lnmp_php;
--network:為容器指定一個網絡環境為lnmp網絡;
--mout: 把宿主機的/app/wwwroot目錄掛載到容器的/usr/local/nginx/html目錄,掛載也相當於數據持久化;
php:5.6.31:指定剛才構建的php鏡像來啟動容器;
查看php容器是否運行:
[root@ganbing php]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5676b229125a php:5.6.31 "./sbin/php-fpm -c /…" 3 seconds ago Up 3 seconds 9000/tcp lnmp_php
7.3 創建nginx容器
創建容器:
[root@ganbing php]# docker run -itd --name lnmp_nginx --network lnmp -p 80:80 --mount type=bind,src=/app/wwwroot,dst=/usr/local/nginx/html nginx:1.12.1 5468c0acc0246eea4f931361218656721666f1ed4a292bb425f25880880e2b10
上面的參數和創建php容器的參數差不多
查看nginx容器是否運行:
[root@ganbing php]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5468c0acc024 nginx:1.12.1 "./sbin/nginx -g 'da…" 30 seconds ago Up 29 seconds 0.0.0.0:80->80/tcp lnmp_nginx
-l:這個參數的意思是顯示最后創建的容器
7.4 測試訪問
其實到了這一步,我們可以創建一個index.html靜態頁面來訪問一下:
[root@ganbing wwwroot]# echo "Dockerfile lnmp test" > /app/wwwroot/index.html
我們把宿主機的/app/wwwroot目錄已經掛載到容器的/usr/local/nginx/html目錄中,所以直接弄個index.html來測試就行。
用瀏覽器訪問這台宿主機的ip:
我們在弄個index.php文件來測試一下:
[root@ganbing wwwroot]# echo "<? phpinfo();" > /app/wwwroot/index.php
訪問一下這個php頁面,是不是也沒問題:
到了這一步,說明nginx、php的環境是弄好了,下面我們來把mysql數據庫容器跑起來,來完成lnmp的平台,mysql數據庫我這里就不用dockerfile來構建了,我直接用官方的鏡像啟動。
7.5 創建mysql容器
在創建容器前,我們創建一個數據卷mysql-volume,把它掛載到mysql容器中,實現數據持久化:
[root@ganbing /]# docker volume create mysql-volume mysql-volume
啟動mysql容器,如果你本地有mysql鏡像,它會引用本的的鏡像,如果沒有它會去docker hub中拉取:
[root@ganbing /]# docker run -itd --name lnmp_mysql --network lnmp -p 3306:3306 --mount src=mysql-volume,dst=/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql --character-set-server=utf8
參數說明:啟動mysql的參數是參考官方鏡像的 https://hub.docker.com/_/mysql/ ,引用官方的mysq鏡像啟動時必須要設定一個root密碼的環境變量.
查看mysql容器是否啟動:
[root@ganbing /]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 871d06d2b425 mysql "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:3306->3306/tcp lnmp_mysql
創建數據庫wordpress:
docker exec lnmp_mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e"create database wordpress"'
查看wordpress庫是否創建 :
[root@ganbing /]# docker exec lnmp_mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e"show databases"' mysql: [Warning] Using a password on the command line interface can be insecure. Database information_schema mysql performance_schema sys wordpress
查看數據卷是否同步了wordpress庫:
[root@ganbing /]# ls /var/lib/docker/volumes/mysql-volume/_data/ auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem wordpress
8、下載wordpress博客系統測試lnmp
下載至/app/wwwroot目錄下:
[root@ganbing /]# cd /app/wwwroot/ [root@ganbing wwwroot]# wget https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz --2018-03-01 13:52:05-- https://cn.wordpress.org/wordpress-4.7.4-zh_CN.tar.gz Resolving cn.wordpress.org (cn.wordpress.org)... 198.143.164.252 Connecting to cn.wordpress.org (cn.wordpress.org)|198.143.164.252|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 8507412 (8.1M) [application/octet-stream] Saving to: ‘wordpress-4.7.4-zh_CN.tar.gz’ 100%[=========================================================>] 8,507,412 1.08MB/s in 8.9s 2018-03-01 13:52:14 (933 KB/s) - ‘wordpress-4.7.4-zh_CN.tar.gz’ saved [8507412/8507412]
解壓並訪問測試:
[root@ganbing wwwroot]# tar -zxvf wordpress-4.7.4-zh_CN.tar.gz
解壓完了之后用瀏覽器訪問:
http://容器宿主機IP/wordpress
配置wordpress博客:
9、dockerfile實踐心行
-
謹慎選擇基礎鏡像
選擇基礎鏡像時,盡量選擇當前官方鏡像庫中的鏡像。 -
充分利用緩存
Docker daemon會順序執行Dockerfile中的指令,而且一旦緩存失效,后續命令將不能使用緩存。為了有效地利用緩存,需要保證指令的連續性,盡量將所有Dockerfile文件中相同的部分都放在前面,而將不同的部分放在后面。 -
正確使用ADD和COPY指令
盡管ADD和COPY用法和作用很相近,但COPY仍是首選。COPY相對ADD而言,功能簡單夠用。 -
RUN指令易讀
為了使Dockerfile易讀、易理解和可維護,在使用比較長的RUN指令時可以使用反斜杠\ 分隔多行。 - 不要在Dockerfile中做端口映射
Docker的兩個核心概念是可重復性和可移植性,鏡像應該可以在任何主機上運行多次。使用Dockerfile的EXPOSE指令,雖然可以將容器端口映射到主機端口上,但會破壞Docker的可移植性,且這樣的鏡像在一台主機上只能啟動一個容器。所以端口映射應在docker run 命令中用-p 參數指定。
#不要在Dockerfile中做如下映射
EXPOSE 80:8080
#僅僅暴露80端口,需要另做映射
EXPOSE 80