什么是Docker?
Docker VS VM
為什么要用docker
Docker相關概念
鏡像Image
容器Container
數據卷Volume
連接Link
倉庫Repository
基於Docker創建LNMP環境
下載鏡像
創建數據盤
創建網絡
創建php-fpm、nginx、mysql鏡像
創建測試頁
連接MySQL
Docker-Compose創建LNMP環境
容器中nginx不記錄日志的問題
https://docs.docker.com/
前言
什么是Docker?
Docker是一個開放源代碼軟件項目,讓應用程序布署在軟件容器下的工作可以自動化進行,借此在Linux操作系統上,提供一個額外的軟件抽象層,以及操作系統層虛擬化的自動管理機制。Docker利用Linux核心中的資源分離機制,例如cgroups,以及Linux核心命名空間(name space),來建立獨立的軟件容器(containers)。這可以在單一Linux實體下運作,避免啟動一個虛擬機器造成的額外負擔。
Docker VS VM
Docker守護進程可以直接與主操作系統進行通信,為各個Docker容器分配資源;它還可以將容器與主操作系統隔離,並將各個容器互相隔離。而虛擬機VM是主操作系統Hypervisor對硬件資源進行虛擬化出獨立的子操作系統,資源並不共用。
為什么要用docker
1、保證線下的開發環境、測試環境和線上的生產環境一致。
2、相比於VM,啟動速度快,資源利用率高,性能開銷小
3、DevOps
4、微服務,一個服務只做好一件事
5、自動執行設置和配置開發環境的重復任務,以便開發人員可以專注於重要的事情:構建出優秀的軟件。
Docker相關概念
鏡像Image
Docker 鏡像就是一個只讀的模板。鏡像可以用來創建 Docker 容器。
Docker 提供了一個很簡單的機制來創建鏡像或者更新現有的鏡像,用戶甚至可以直接從其他人那里下載一個已經做好的鏡像來直接使用。
鏡像=操作系統+軟件運行環境+用戶程序
例如:一個鏡像可以包含一個完整的 ubuntu 操作系統環境,里面僅安裝了 Apache 或用戶需要的其它應用程序。
我們可以通過編寫 Dockerfile 來創建鏡像。
容器Container
Docker 利用容器來運行應用。
容器是從鏡像創建的運行實例。它可以被啟動、開始、停止、刪除。每個容器都是相互隔離的、保證安全的平台。
可以把容器看做是一個簡易版的 Linux 環境(包括root用戶權限、進程空間、用戶空間和網絡空間等)和運行在其中的應用程序。
注:鏡像是只讀的,容器在啟動的時候創建一層可寫層作為最上層。
數據卷Volume
數據卷讓你可以不受容器生命周期影響進行數據持久化。
使用docker的時候必須做出的思維改變是:容器應該是短暫和一次性的.
連接Link
容器啟動的時候,將被分配一個隨機的私有IP,其它容器可以使用這個IP地址與其進行通訊。這很重要,原因有二:一是它提供了榮期間相互通信的渠道,二是容器將共享一個本地網絡。
要開啟容器間通訊,docker允許你在創建一個新容器時引用其它現存容器,在你剛創建的容器里被引用的容器將獲得一個(你指定的)別名。我們就說,這兩個容器鏈接在了一起。
因此,如果DB容器已經在運行,我們可以創建一個web服務器容器,並在創建時引用這個DB容器,給它起一個別名,比如dbapp。在這個新建的web服務器容器里,我可以在任何時候使用主機名dbapp與DB容器進行通訊。
倉庫Repository
倉庫是集中存放鏡像文件的場所。有時候會把倉庫和倉庫注冊服務器(Registry)混為一談,並不嚴格區分。實際上,倉庫注冊服務器上往往存放着多個倉庫,每個倉庫中又包含了多個鏡像,每個鏡像有不同的標簽(tag)。
倉庫分為公開倉庫(Public)和私有倉庫(Private)兩種形式。
最大的公開倉庫是 Docker Hub,存放了數量龐大的鏡像供用戶下載。 國內的公開倉庫包括 Docker Pool等,可以提供大陸用戶更穩定快速的訪問。
當然,用戶也可以在本地網絡內創建一個私有倉庫。
當用戶創建了自己的鏡像之后就可以使用 push 命令將它上傳到公有或者私有倉庫,這樣下次在另外一台機器上使用這個鏡像時候,只需要從倉庫上 pull 下來就可以了。
注:Docker 倉庫的概念跟 Git 類似,注冊服務器可以理解為 GitHub 這樣的托管服務。
基於Docker創建LNMP環境
下載鏡像
docker pull bitnami/php-fpm #下載最新php-fpm鏡像,里面自帶了最新版的php
docker pull nginx #下載最新nginx鏡像
docker pull mysql #下載最新mysql鏡像
創建數據盤
https://docs.docker.com/storage/volumes/
注:
1、如果直接create,文件會由容器管理,否則需要mount指定目錄
2、使用mac的同學需要注意,你會發現在機子上找不到這個路徑,是因為mac的docker實際是運行在虛擬機上的,所以你需要進入docker虛擬機查看
screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty
此時cd /var/lib/docker/volumes/learn/_data/
就是創建的這個volume。
如果覺得麻煩Mac可以跳過這步
docker volume create learn
我們這里直接創建數據盤,會發現實際的路徑是在docker相關目錄下的
~/Documents/code/learn » docker volume inspect learn
[
{
"CreatedAt": "2020-04-15T11:07:22Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/learn/_data",
"Name": "learn",
"Options": {},
"Scope": "local"
}
]
創建網絡
https://docs.docker.com/engine/reference/commandline/network_create/
Docker有以下網絡類型:
bridge:用於獨立container之間的通信
host: 直接使用宿主機的網絡,端口也使用宿主機的
overlay:當有多個docker主機時,跨主機的container通信
macvlan:每個container都有一個虛擬的MAC地址
none: 禁用網絡
默認情況下,docker會創建一個橋接網絡,當你創建一個新的容器執行docker run
的時候,將會自動連接到這個橋接網絡,你不能刪除這個默認網絡,但是可以創建一個新的。
Docker在默認情況下,分別會建立一個bridge、一個host和一個none的網絡:
~ » docker network ls
NETWORK ID NAME DRIVER SCOPE
a0bf815f3cb0 bridge bridge local
836b8a7368f8 host host local
8f2915cdc31a none null local
docker network create --subnet=172.54.0.0/24 lnmp #創建B類划分子網絡,方便配置文件中直接使用容器名稱
創建php-fpm、nginx、mysql鏡像
https://docs.docker.com/engine/reference/commandline/run/
docker run -d --name php -v learn:/var/www --net lnmp --restart=always bitnami/php-fpm
docker run -d --name nginx -p 80:80 -v learn:/var/www --net lnmp --restart=always nginx
docker run -d --name mysql --restart=always -p3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --net lnmp mysql
mac下:
docker run -d --name php -v /Users/lixin/Documents/code/learn:/var/www --net lnmp --restart=always bitnami/php-fpm
docker run -d --name nginx -p 80:80 -v /Users/lixin/Documents/code/learn:/var/www --net lnmp --restart=always nginx
docker run -d --name mysql --restart=always -p3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --net lnmp mysql
修改配置文件
#導出文件
docker cp default.conf nginx:/etc/nginx/conf.d/default.conf
#導入文件
docker cp nginx:/etc/nginx/conf.d/default.conf default.conf
修改示例如下。
server {
listen 80;
server_name localhost;
location / {
root /var/www;
index index.html index.htm index.php;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ \.php$ {
root /var/www;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
然后重啟nginx
docker restart nginx
創建測試頁
<?php
phpinfo();
?>
linux下:
將文件移動到數據卷目錄下(web根目錄就在這個目錄下)
mv index.php /var/lib/docker/volumes/webpage/_data/
mac下:
直接在mount的目錄下創建文件即可。
然后訪問localhost
連接MySQL
創建測試文件
<?php
$link = mysqli_connect('mysql', 'root', '123456');
if (!$link) {
die('Could not connect: ' . mysqli_connect_error());
}
echo 'Connected successfully';
mysqli_close($link);
?>
訪問之后你會發現報錯:【Could not connect: The server requested authentication method unknown to the client】
這是因為MySQL8.0之后調整了認證加密插件,而php的連接庫還不支持(參考這里,還有這里)。
解決方案:
1、進入容器
2、登錄mysql
3、執行ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY '123456';
用原插件重新設置一次密碼。
~ » docker exec -it mysql /bin/sh;exit
# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.19 MySQL Community Server - GPL
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY '123456';
Query OK, 0 rows affected (0.01 sec)
mysql>
刷新:Connected successfully
Docker-Compose創建LNMP環境
Docker-Compose項目是Docker官方的開源項目,負責實現對Docker容器集群的快速編排。
Docker-Compose將所管理的容器分為三層,分別是工程(project),服務(service)以及容器(container)。Docker-Compose運行目錄下的所有文件(docker-compose.yml,extends文件或環境變量文件等)組成一個工程,若無特殊指定工程名即為當前目錄名。一個工程當中可包含多個服務,每個服務中定義了容器運行的鏡像,參數,依賴。一個服務當中可包括多個容器實例,Docker-Compose並沒有解決負載均衡的問題,因此需要借助其它工具實現服務發現及負載均衡。
Docker-Compose的工程配置文件默認為docker-compose.yml,可通過環境變量COMPOSE_FILE或-f參數自定義配置文件,其定義了多個有依賴關系的服務及每個服務運行的容器。
使用一個Dockerfile模板文件,可以讓用戶很方便的定義一個單獨的應用容器。在工作中,經常會碰到需要多個容器相互配合來完成某項任務的情況。例如要實現一個Web項目,除了Web服務容器本身,往往還需要再加上后端的數據庫服務容器,甚至還包括負載均衡容器等。
Compose允許用戶通過一個單獨的docker-compose.yml模板文件(YAML 格式)來定義一組相關聯的應用容器為一個項目(project)。
Docker-Compose項目由Python編寫,調用Docker服務提供的API來對容器進行管理。因此,只要所操作的平台支持Docker API,就可以在其上利用Compose來進行編排管理。
https://docs.docker.com/compose/
https://docs.docker.com/compose/install/
https://docs.docker.com/compose/gettingstarted/
https://docs.docker.com/compose/compose-file/
注:
1、mac的桌面版Docker自帶compose,所以不需要安裝了。
2、也可以考慮用docker stack
如果需要經常到一個新的機子上搭建環境,像上面那樣每次都一個一個創建就很麻煩了,這個時候可以使用docker-compose,通過YAML來定義軟件服務,最后只需要一個命令,就能創建並允許所有定義到的服務。
通常使用compse基於下列三個步驟:
- 基於dockerfile定義好程序的運行環境,這樣你可以在任何情況下復用。(如果不需要build,這個步驟可以忽略,直接用現成的image)
- 基於docker-compose.yml來定義服務,這樣可以在隔離的環境下同時運行。
- 運行docker-compose up 來創建並運行整個程序。
可以用於開發環境、自動化測試、單機部署。
示例文件如下:
version: '3'
services:
php:
container_name: php
image: "bitnami/php-fpm"
networks:
- lnmp
volumes:
- /Users/lixin/Documents/code/learn:/var/www
restart: always
nginx:
container_name: nginx
image: "nginx"
ports:
- "80:80"
volumes:
- /Users/lixin/Documents/code/learn:/var/www
networks:
- lnmp
restart: always
mysql:
container_name: mysql
image: "mysql"
ports:
- "3306:3306"
networks:
- lnmp
restart: always
environment:
MYSQL_ROOT_PASSWORD: "123456"
networks:
lnmp:
ipam:
driver: default
config:
- subnet: "172.54.0.0/24"
然后保存為docker-compose.yml
將文件放置於一個專門存放的compose相關的目錄里執行命令
~/Documents/code/learn » docker-compose up -d
Starting php ... done
Starting nginx ... done
Starting mysql ... done
注:基於compose創建的容器會放在以docker-compose.yml
的目錄為名稱的容器組下面
容器中nginx不記錄日志的問題
使用過程中你會發現,即使nginx的conf設置了訪問日志,錯誤日志,但是卻沒有寫入到相應的文件里。
這是因為nginx官方默認已經設置了直接輸出到Docker的日志收集器里。
FROM debian:jessie
MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"
ENV NGINX_VERSION 1.11.5-1~jessie
RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \
&& echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y \
ca-certificates \
nginx=${NGINX_VERSION} \
nginx-module-xslt \
nginx-module-geoip \
nginx-module-image-filter \
nginx-module-perl \
nginx-module-njs \
gettext-base \
&& rm -rf /var/lib/apt/lists/*
# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
注:The official nginx image creates a symbolic link from /var/log/nginx/access.log to /dev/stdout, and creates another symbolic link from /var/log/nginx/error.log to /dev/stderr, overwriting the log files and causing logs to be sent to the relevant special device instead. See the Dockerfile.