一、Docker概述
1、Docker是什么?
使用最广泛的开源容器引擎
一种操作系统级的虚拟化技术
依赖于Linux内核特性:Namespace(资源隔离)和Cgroups(资源限制)
一个简单的应用程序打包工具
2、Docker基本组成
Docker Client:客户端
Ddocker Daemon:守护进程
Docker Images:镜像
Docker Container:容器
Docker Registry:镜像仓库
二、Docker安装
1、Docker版本
社区版(Community Edition,CE)
企业版(Enterprise Edition,EE)
2、支持平台
Linux(CentOS,Debian,Fedora,Oracle Linux,RHEL,SUSE和Ubuntu)
Mac
Windows
3、MAC系统安装Docker
macOS 使用 Homebrew 安装 Docker Desktop CE
系统要求:系统最低为 macOS Sierra 10.12。
安装命令:
$ brew cask install docker
$ docker --version
三、镜像管理
1、镜像是什么
• 一个分层存储的文件
• 一个软件的环境
• 一个镜像可以创建N个容器
• 一种标准化的交付
镜像不是一个单一的文件,而是有多层构成。我们可以通过docker history <ID/NAME> 查看镜像中各层内容及大小,每层 对应着Dockerfile中的一条指令。Docker镜像默认存储在/var/lib/docker/<storage-driver>中。
镜像从哪里来?
Docker Hub是由Docker公司负责维护的公共注册中心,包含大量的容器镜像,Docker工具默认从这个公共镜像库下载镜像。 地址:https://hub.docker.com/explore
配置镜像加速器:
右键点击桌面顶栏的 docker 图标,选择 Preferences ,在 Daemon 标签(Docker 17.03 之前版本为 Advanced 标签)下的 Registry mirrors 列表中将
https://yp7fjc4v.mirror.aliyuncs.com加到"registry-mirrors"的数组里,点击 Apply & Restart按钮,等待Docker重启并应用配置的镜像加速器。
2、镜像与容器联系
如图,容器其实是在镜像的最上面加了一层读写层,改动运行容器里的文件时, 会先从镜像里要写的文件复制到容器自己的文件系统中(读写层)。 如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作的,并不会修改镜像的源文件,这种方式提高磁盘利用率。 若想持久化这些改动,可以通过docker commit 将容器保存成一个新镜像。
3、管理镜像常用命令
查看docker 命令的用法:docker --help
查看管理镜像常用命令image 的用法:docker image --help
指令 | 描述 |
---|---|
ls | 列出镜像 |
build | 构建镜像来自Dockerfile |
history | 查看镜像历史 |
inspect | 显示一个或多个镜像详细信息 |
pull | 从镜像仓库拉取镜像 |
push | 推送一个镜像到镜像仓库 |
rm | 移除一个或多个镜像 |
prune | 移除未使用的镜像。没有被标记或被任何容器引用的 |
tag | 创建一个引用源镜像标记目标镜像 |
export | 导出容器文件系统到tar归档文件 |
import | 导入容器文件系统tar归档文件创建镜像 |
save | 保存一个或多个镜像到一个tar归档文件 |
load | 加载镜像来自tar归档或标准输入 |
四、容器管理
1、创建容器常用选项
# docker container --help
选项 | 描述 |
---|---|
-i, –interactive | 交互式 |
-t, –tty | 分配一个伪终端 |
-d, –detach | 运行容器到后台 |
-e, –env | 设置环境变量 |
-p, –publish list | 发布容器端口到主机 |
-P, –publish-all | 发布容器所有EXPOSE的端口到宿主机随机端口 |
–name string | 指定容器名称 |
-h, –hostname | 设置容器主机名 |
–ip string | 指定容器IP,只能用于自定义网络 |
–network | 连接容器到一个网络 |
–mount mount | 将文件系统附加到容器 |
-v, –volume list | 绑定挂载一个卷 |
–restart string | 容器退出时重启策略,默认no,可选值:[always/on-failure] |
2、容器资源限制
选项 | 描述 |
---|---|
-m,–memory | 容器可以使用的最大内存量 |
–memory-swap | 允许交换到磁盘的内存量 |
–memory-swappiness=<0-100> | 容器使用SWAP分区交换的百分比(0-100,默认为-1) |
–oom-kill-disable | 禁用OOM Killer |
–cpus | 可以使用的CPU数量 |
–cpuset-cpus | 限制容器使用特定的CPU核心,如(0-3, 0,1) |
–cpu-shares | CPU共享(相对权重) |
3、管理容器常用命令
选项 | 描述 |
---|---|
ls | 列出容器 |
inspect | 查看一个或多个容器详细信息 |
exec | 在运行容器中执行命令 |
commit | 创建一个新镜像来自一个容器 |
cp | 拷贝文件/文件夹到一个容器 |
logs | 获取一个容器日志 |
port | 列出或指定容器端口映射 |
top | 显示一个容器运行的进程 |
stats | 显示容器资源使用统计 |
stop/start | 停止/启动一个或多个容器 |
rm | 删除一个或多个容器 |
update | 表更资源的更新 |
五、管理容器里应用程序数据
Docker提供三种方式将数据从宿主机挂载到容器中:
• volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。
• bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中。
• tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用 tmpfs,同时避免写入容器可写层提高性能。
1、Volume
管理卷:
# docker volume create nginx-vol
# docker volume ls
# docker volume inspect nginx-vol
用卷创建一个容器:
# docker run -d --name=nginx-test --mount src=nginx-vol,dst=/usr/share/nginx/html nginx
清理:
# docker stop nginx-test
# docker rm nginx-test
# docker volume rm nginx-vol
注意:
- 如果没有指定卷,自动创建。
2、Bind Mounts
用卷创建一个容器:
$ mkdir -p $(pwd)/apps/wwwroot
$ docker run -d -it --name=nginx-test --mount type=bind,src=$(pwd)/apps/wwwroot,dst=/usr/share/nginx/html nginx
验证绑定:
$ docker inspect nginx-test
清理:
$ docker stop nginx-test
$ docker rm nginx-test
注意:
- 如果源文件/目录没有存在,不会自动创建,会抛出一个错误。
- 如果挂载目标在容器中非空目录,则该目录现有内容将被隐藏。
六、容器网络
网络模式
• bridge
–net=bridge 默认网络,Docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中。
• 自定义网络 与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信。
• host –net=host
容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主
机的。容器除了网络,其他都是隔离的。
• none
–net=none
获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。
• container
–net=container:Name/ID
与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。
七、Dockerfile
1. Dockerfile格式
从上往下执行:
FROM centos:latest
MAINTAINER liuzhousheng
RUN yum install gcc -y
COPY run.sh /usr/bin
EXPOSE 80
CMD [“run.sh”]
2. Dockerfile指令
指令 | 描述 |
---|---|
FROM | 构建新镜像是基于哪个镜像 |
MAINTAINER | 镜像维护者姓名或邮箱地址 |
RUN | 构建镜像时运行的Shell命令 |
COPY | 拷贝文件或目录到镜像中 |
ENV | 设置环境变量 |
USER | 为RUN、CMD和ENTRYPOINT执行命令指定运行用户 |
EXPOSE | 声明容器运行的服务端口 |
HEALTHCHECK | 容器中服务健康检查 |
WORKDIR | 为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录 |
ENTRYPOINT | 运行容器时执行,如果有多个ENTRYPOINT指令,最后一个生效 |
CMD | 运行容器时执行,如果有多个CMD指令,最后一个生效 |
3. Build镜像
Usage: docker build [OPTIONS] PATH | URL | - [flags] Options:
-t, --tag list # 镜像名称
-f, --file string # 指定Dockerfile文件位置
# docker build .
# docker build -t shykes/myapp .
# docker build -t shykes/myapp -f /path/Dockerfile /path
# docker build -t shykes/myapp http://www.example.com/Dockerfile
4. 构建Nginx,PHP基础镜像
• 构建Nginx基础镜像
FROM centos:7
MAINTAINER liuzhousheng
RUN yum install -y gcc gcc-c++ make \
openssl-devel pcre-devel gd-devel \
iproute net-tools telnet wget curl && \
yum clean all && \
rm -rf /var/cache/yum/*
RUN wget http://nginx.org/download/nginx-1.15.5.tar.gz && \
tar zxf nginx-1.15.5.tar.gz && \
cd nginx-1.15.5 &&\
./configure --prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_stub_status_module && \
make -j 4 && make install && \
rm -rf /usr/local/nginx/html/* && \
echo "ok" >> /usr/local/nginx/html/status.html && \
cd / && rm -rf nginx-1.12.2* && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ENV PATH $PATH:/usr/local/nginx/sbin
#COPY nginx.conf /usr/local/nginx/conf/nginx.conf ## 先注释这行,不然构建需要依赖本地配置文件,启动启动容器会依赖php
WORKDIR /usr/local/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
运行命令:
# docker build -t nginx:v1 -f dockerfile-nginx .
# docker image ls
# docker run -d --name nginx01 -p 88:80 nginx:v1
# docker ps -l
# curl 10.40.6.165:88/status.html
用刚刚创建的nginx:v1 镜像在创建一个v2镜像
# cat index.html ## 将这文件作为nginx root目录
hello docker!!!
# cat dockerfile-nginxv2 ## 新的dockerfile
FROM nginx:v1
COPY index.html /usr/local/nginx/html/
# docker build -t nginx:v2 -f dockerfile-nginxv2 . ## 创建nginx:v2镜像
Sending build context to Docker daemon 410.1kB
Step 1/2 : FROM nginx:v1
---> db3cfa07d4a5
Step 2/2 : COPY index.html /usr/local/nginx/html
---> 64f743ec5b18
Successfully built 64f743ec5b18
Successfully tagged nginx:v2
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v2 64f743ec5b18 27 seconds ago 395MB
nginx v1 db3cfa07d4a5 11 minutes ago 395MB
# docker run -d --name nginx02 -p 89:80 nginx:v2
c446b345b73ac6417d7090b5d46c7be574b87be152ad7c9f42886e86e43f4d06
# curl 10.40.6.165:89
hello docker!!!
• 构建PHP基础镜像
FROM centos:7
MAINTAINER liuzhousheng
RUN yum install epel-release -y && \
yum install -y gcc gcc-c++ make gd-devel libxml2-devel \
libcurl-devel libjpeg-devel libpng-devel openssl-devel \
libmcrypt-devel libxslt-devel libtidy-devel autoconf \
iproute net-tools telnet wget curl && \
yum clean all && \
rm -rf /var/cache/yum/*
RUN wget http://docs.php.net/distributions/php-5.6.36.tar.gz && \
tar zxf php-5.6.36.tar.gz && \
cd php-5.6.36 && \
./configure --prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--enable-fpm --enable-opcache \
--with-mysql --with-mysqli --with-pdo-mysql \
--with-openssl --with-zlib --with-curl --with-gd \
--with-jpeg-dir --with-png-dir --with-freetype-dir \
--enable-mbstring --with-mcrypt --enable-hash && \
make -j 4 && make install && \
cp php.ini-production /usr/local/php/etc/php.ini && \
cp sapi/fpm/php-fpm.conf /usr/local/php/etc/php-fpm.conf && \
sed -i "90a \daemonize = no" /usr/local/php/etc/php-fpm.conf && \
mkdir /usr/local/php/log && \
cd / && rm -rf php* && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ENV PATH $PATH:/usr/local/php/sbin:/usr/local/php/bin
COPY php.ini /usr/local/php/etc/
COPY php-fpm.conf /usr/local/php/etc/
WORKDIR /usr/local/php
EXPOSE 9000
CMD ["php-fpm"]
运行命令构建:
# docker build -t php:v1 -f dockerfile-php .
# docker image ls
# docker run -d --name php01 php:v1
# docker ps -l
八、快速搭建LNMP网站平台
lnmp 架构要用到三个容器,所以要准备相应的三个镜像:
php: php:v1(上边我们自己制作的镜像)
nginx: nginx:v1(上边我们自己制作的镜像)
mysql: mysql:5.7(使用官方镜像)
# docker pull mysql:5.7
(1)、自定义网络
# docker network create net-lnmp
(2)、创建Mysql容器
$ mkdir -p /Users/liuzhousheng/docker/data/mysql
$ docker run -d --name lnmp_mysql --net net-lnmp --mount type=bind,src=/Users/liuzhousheng/docker/data/mysql,dst=/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress mysql:5.7 --character-set-server=utf8
(3)、创建PHP容器
$ mkdir -p ~/apps/wwwroot
$ docker run -d --name lnmp_php --net net-lnmp --mount type=bind,src=/Users/liuzhousheng/apps/wwwroot,dst=/wwwroot php:v1
(4)、创建Nginx容器
nginx.conf配置文件:
user nobody;
worker_processes 4;
worker_rlimit_nofile 65535;
error_log logs/error.log notice;
pid /var/run/nginx.pid;
events {
use epoll;
worker_connections 4096;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log off;
keepalive_timeout 65;
client_max_body_size 64m;
server {
listen 80;
server_name www.lnmp_test.com;
index index.php index.html;
access_log logs/www.lnmp_test.com_access.log;
error_log logs/www.lnmp_test.com_error.log;
# location ~ .*\.(js|css|html|png|gif|jpg|jpeg)$ {
location / {
root /wwwroot;
}
location ~* \.php$ {
root /wwwroot;
fastcgi_pass lnmp_php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
启动容器:
$ mkdir -p /Users/liuzhousheng/apps/logs/wordpress/nginx
$ docker run -d --name lnmp_nginx --net net-lnmp -p 88:80 --mount type=bind,src=$(pwd)/nginx.conf,dst=/usr/local/nginx/conf/nginx.conf --mount type=bind,src=/Users/liuzhousheng/apps/wwwroot,dst=/wwwroot --mount type=bind,src=/Users/liuzhousheng/apps/logs/wordpress/nginx,dst=/usr/local/nginx/logs nginx:v1
查看三个容器:
# docker ps
创建php测试页:
$cat ~/apps/wwwroot/test.php
<?php
phpinfo()
?>
## 浏览器请求URL:http://10.40.6.165:88/test.php
(5)、以wordpress博客为例
https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
# cd ~/apps/wwwroot
# wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
# tar xvf wordpress-4.9.4-zh_CN.tar.gz
使用浏览器访问 http://10.40.6.165:88/wordpress
进入容器 lnmp_nginx查看nginx访问日志:
# docker exec -it lnmp_nginx bash
[root@f8c38e7b7a95 nginx]# tail -f logs/www.lnmp_test.com_access.log
10.19.1.28 - - [15/May/2019:17:13:42 +0800] "POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1" 200 58 "http://10.40.6.165:88/wordpress/wp-admin/edit.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"
10.19.1.28 - - [15/May/2019:17:13:43 +0800] "GET /wordpress/wp-includes/js/wp-emoji-release.min.js?ver=4.9.10 HTTP/1.1" 304 0 "http://10.40.6.165:88/wordpress/wp-admin/edit.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"
10.19.1.28 - - [15/May/2019:17:13:43 +0800] "GET /wordpress/wp-admin/edit.php HTTP/1.1" 200 48058 "http://10.40.6.165:88/wordpress/wp-admin/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"
10.19.1.28 - - [15/May/2019:17:13:43 +0800] "POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1" 200 58 "http://10.40.6.165:88/wordpress/wp-admin/edit.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"