目录
- 二进制安装Docker 1
- Docker镜像管理 2
2.1. 镜像是什么 2
2.2. 镜像与容器联系 2
2.3. 管理镜像常用命令 2
2.3.1. docke查看镜像信息及镜像详细信息 3
2.3.2. docker拉取镜像 3
2.3.3. docker移除(删除)镜像 3
2.3.4. docker移除未使用的镜像。没有被标记或被任何容器引用的 3
2.3.5. export导出容器文件系统到tar归档文件 3
2.3.6. tar保存一个或多个镜像到一个tar归档文件 4
2.3.7. load加载镜像来自tar归档或标准输入(导入) 4
2.3.8. docker出现IPv4 forwarding is disabled. Networking will not work解决方法 4
2.4. 镜像存储核心技术:联合文件系统UFS 4
2.5. 镜像存储核心技术:写时复制COW 4 - Docker容器管理 5
3.1. 创建容器常用选项 5
3.1.1. 直接运行一个容器并进入到容器 5
3.1.2. 后台运行一个容器 5
3.1.3. 查看最新运行的容器 6
3.1.4. 查看容器进程 6
3.1.5. 进入到容器 6
3.1.6. 容器环境变量-e,-env 6
3.2. 容器资源限制 6
3.2.1. 内存限额 6
3.2.2. CPU限额 7
3.3. 容器配额扩容 7
3.3.1. 查看容器资源限额 7
3.3.2. 更新容器内存限额 7
3.4. 容器常用命令 7
3.4.1. 创建容器 7
3.4.2. 进入容器 8
3.4.3. 查看容器列表 8
3.4.4. 查看容器详细信息 8
3.4.5. 批量强制删除所有容器 8
3.4.6. 拷贝文件/文件夹到一个容器 8
3.4.7. 把容器中的文件/文件夹拷贝出来 8
3.4.8. 以现有的运行容器提交成一个或制作成一个新的镜像 8
3.4.9. 直接运行容器shell命令 9
3.5. 容器实现核心技术:Namespace 9
3.6. 容器实现核心技术:CGroups 9
3.7. Docker核心组件之间关系 10 - Docker 容器数据持久化 11
4.1. 数据卷(Volume) 11
4.1.1. 查看数据卷 11
4.1.2. 创建数据卷 11
4.1.3. 查看数据卷详细信息 11
4.1.4. 用数据卷(使用-v参数)创建一个容器 11
4.1.5. 用数据卷(使用–mount参数)创建容器 12
4.1.6. 清理数据卷 12
4.2. 挂载宿主机数据(Bind Mounts) 12
4.2.1. 将宿主机目录挂载到容器目录(使用-v参数) 12
4.2.2. 将宿主机目录挂载到容器目录(使用—mount 参数) 12
4.3. Volume特点 13
4.4. Bind Mounts特点 13 - Docker 容器网络 13
5.1. 网络模式:bridge详解 14
5.1.1. 查看当前网络 14
5.1.2. 查看网络详细信息 14
5.1.3. 查看网桥 14
5.1.4. 创建自定义网络 14
5.1.5. 使用创建的自定义网络 14
5.2. 网络模式:host、none和container详解 15
5.2.1. Host 15
5.2.2. none 16
5.2.3. container 16
5.2.4. 重装docker.0虚拟网卡 17
5.3. Docker网络模型与容器网络访问流程 17
5.3.1. Docker网络模型 17
5.3.2. 容器网络访问原理 17
5.4. 容器网络实现核心技术:Iptables 18
5.5. 跨主机网络:实现Docker容器多主机通信 19
5.5.1. 安装etcd 20
5.5.2. flanneld安装并配置 20
5.5.3. 向etcd写入子网 20
5.5.4. 配置Docker使用flannel生成的网络信息 21
5.5.5. 在两台主机创建容器相互ping验证 21 - Dockerfile制作容器镜像 22
6.1. Dockerfile常用指令及使用 22
6.2. docker build构建镜像 22
6.3. CMD与ENTRYPOINT区别 23
6.3.1. CMD用法 23
6.3.2. ENTRYPOINT用法 25
6.3.3. ENTRYPOINT与CMD配合使用,CMD:作为ENTRYPOINT的默认参数 26
6.4. Docker解决每次进入容器命令都要重新source /etc/profile 才能生效的问题 27
6.5. 前端项目镜像制作:openresty(nginx) 28
6.6. 构建Tomcat镜像 31
6.7. PHP项目镜像制作:PHP5.6 32 - docker部署LNMP网站平台 33
- Docker 图形化管理 35
1.二进制安装Docker
https://docs.docker.com/
[root@docker ~]#wget https://download.docker.com/linux/static/stable/x86_64/docker-19.03.9.tgz
以下在所有节点操作。这里采用二进制安装,用yum安装也一样。
解压二进制包
[root@docker ~]#tar zxvf docker-19.03.9.tgz
[root@docker ~]#mv docker/* /usr/bin
systemd管理docker
cat > /usr/lib/systemd/system/docker.service << EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
EOF
创建配置文件
[root@docker ~]#mkdir /etc/docker
[root@docker ~]#
cat > /etc/docker/daemon.json << EOF
{
“registry-mirrors”: [“https://b9pmyelo.mirror.aliyuncs.com”]
}
EOF
registry-mirrors 阿里云镜像加速器
启动并设置开机启动
[root@docker ~]#systemctl daemon-reload
[root@docker ~]#systemctl start docker
[root@docker ~]#systemctl enable docker
查看安装docker的相关信息
[root@slave ~]# docker info
2.Docker镜像管理
2.1.镜像是什么
镜像是什么?
• 一个分层存储的文件
• 一个软件的环境
• 一个镜像可以创建N个容器
• 一种标准化的交付
• 一个不包含Linux内核而又精简的Linux操作系统
镜像不是一个单一的文件,而是有多层构成。我们可以通过docker history <ID/NAME> 查看镜像中各层内容及大小,每层
对应着Dockerfile中的一条指令。Docker镜像默认存储在/var/lib/docker/<storage-driver>中。
镜像从哪里来?
Docker Hub是由Docker公司负责维护的公共注册中心,包含大量的容器镜像,Docker工具默认从这个公共镜像库下载镜像。
地址:https://hub.docker.com/explore,可以在上面注册一个账号,并可以上传自定义镜像
2.2.镜像与容器联系
镜像:类似于虚拟机镜像,一个只读模板
容器:通过镜像创建的运行实例
容器其实是在镜像的最上面加了一层读写层,在运行容器里文件改动时,
会先从镜像里要写的文件复制到容器自己的文件系统中(读写层)。
如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多
少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作
的,并不会修改镜像的源文件,这种方式提高磁盘利用率。
若想持久化这些改动,可以通过docker commit 将容器保存成一个新镜像。
2.3.管理镜像常用命令
[root@slave ~]# docker image --help
指令 描述
ls 列出镜像
Build 构建镜像来自Dockerfile
history 查看镜像历史
inspect 显示一个或多个镜像详细信息
pull 从镜像仓库拉取镜像
push 推送一个镜像到镜像仓库
rm 移除一个或多个镜像
prune 移除未使用的镜像。没有被标记或被任何容器引用的
tag 创建一个引用源镜像标记目录镜像
export 导出容器文件系统到tar归档文件
import 导入容器文件系统tar归档文件创建镜像
save 保存一个或多个镜像到一个tar归档文件
load 加载镜像来自tar归档或标准输入
2.3.1.docke查看镜像信息及镜像详细信息
[root@slave ~]# docker images
[root@slave ~]# docker inspect nginx
[root@slave ~]# docker inspect 4bb46517cac3
2.3.2.docker拉取镜像
拉取nginx 1.17版本镜像
[root@slave ~]# docker pull nginx:1.17
2.3.3.docker移除(删除)镜像
删除1.17版本nginx 镜像
[root@slave ~]# docker image rm nginx:1.17
强制删除nginx镜像
[root@slave ~]# docker image rm -f nginx
2.3.4.docker移除未使用的镜像。没有被标记或被任何容器引用的
[root@slave ~]# docker image prune
移除所有没有被使用的镜像
[root@slave ~]# docker image prune -a
2.3.5.export导出容器文件系统到tar归档文件
先创建一个容器
[root@slave ~]# docker run -d --name nginx01 nginx
[root@slave ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
944734196e96 nginx “/docker-entrypoint.…” About a minute ago Up About a minute 80/tcp nginx01
[root@slave ~]# docker container export 944734196e96 > nginx.tar
[root@slave ~]# du -sh nginx.tar
下载nginx.tar
[root@slave ~]# sz nginx.tar
2.3.6.tar保存一个或多个镜像到一个tar归档文件
[root@slave ~]# docker images
[root@slave ~]# docker save nginx >nginx.tar
[root@slave ~]# du -sh nginx.tar
2.3.7.load加载镜像来自tar归档或标准输入(导入)
[root@slave ~]# docker load < nginx.tar
[root@slave ~]# docker images
2.3.8.docker出现IPv4 forwarding is disabled. Networking will not work解决方法
1.修改内核参数
vi /etc/sysctl.conf
net.ipv4.ip_forward=0
改成
net.ipv4.ip_forward=1
2.重启network服务
systemctl restart network
3.重启docker服务(这一步最重要,如果没有执行的话,还是会报错的)
systemctl restart docker
4.重启iptables
systemctl restart iptables
2.4.镜像存储核心技术:联合文件系统UFS
镜像怎么高效存储?
难道像虚拟机那样一个容器对应一个独立的镜像文件?这样对于密集型容器,磁盘占用率太大!
答:引入联合文件系统,将镜像多层文件联合挂载到容器文件系统
2.5.镜像存储核心技术:写时复制COW
了解联合文件系统后,我们指定,镜像是只读的,类似共享形式让多个容器使用,如果要在容器里修改文件,即镜像里的文件,那该怎么办呢?
答:引入写时复制(copy-on-write),需要修改文件操作时,会先从镜像里把要写的文件复制到自己的文件系统中进行修改。
3.Docker容器管理
3.1.创建容器常用选项
选项 描述
-i,-interactive 交互式
-t,tty 分配一个伪终端
-d,-detach 运行容器到后台
-e,-env 设置环境变量
-p,-publish list 发布容器端口到主机
-P,-pubilsh-all 发布容器所有EXPOSE的端口到宿主机随机端口
-name string 指定容器名称
-h,-hostname 设置容器主机名
-ip string 指定容器IP,只能用于自定义网络
-network 连接容器到一个网络
-mount mount 将文件系统附加到容器
-v,-volume list 绑定挂载一个卷
-restart string 容器退出时重启策略,默认no,可选值:[always|on-failure]
[root@slave ~]# docker container --help
3.1.1.直接运行一个容器并进入到容器
[root@slave ~]docker run -it centos /bin/bash
3.1.2.后台运行一个容器
[root@slave ~]sudo docker run -itd centos
3.1.3.查看最新运行的容器
[root@slave ~]# docker ps -l
3.1.4.查看容器进程
[root@slave ~]# docker top 176339efeac9
3.1.5.进入到容器
[root@slave ~]# docker container exec -it 176339efeac9 bash
3.1.6.容器环境变量-e,-env
运行一个名为web的容器,并设置容器环境变量test=123456,宿主机的88端口转发容器的80端口,以nginx最新版的镜像来运行!
[root@slave ~]sudo docker container run -d --name web -e test=123456 -p 88:80 -h web nginx
查看最新运行的容器
[root@slave ~]sudo docker ps -l
进入web容器,并查看test变量
[root@slave ~]sudo docker exec -it web bash
root@web:/# echo $test
123456
3.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.2.1.内存限额
运行一个容器名为nginx03,允许容器最多使用500M内存和100M的Swap,并禁用OOM Killer,
[root@slave ~]# sudo docker run -itd --name nginx03 --memory=“500m” --memory-swap=“600m” --oom-kill-disable nginx
3.2.2.CPU限额
允许容器最多使用一个半的CPU:
[root@slave ~]# docker run -itd --name nginx04 --cpus=“1.5” nginx
允许容器最多使用50%的CPU:
[root@slave ~]# docker run -d --name nginx05 --cpus=".5" nginx
查看容器资源限制
[root@slave ~]# sudo docker stats --no-stream nginx03
3.3.容器配额扩容
docker update 更新容器配置
[root@slave ~]# docker update --help
运行一个内存限额为512M的容器
[root@slave ~]# docker run -d -m=“512m” nginx
[root@slave ~]# docker ps
3.3.1.查看容器资源限额
[root@slave ~]# docker stats eacfa35556b6
3.3.2.更新容器内存限额
[root@slave ~]# docker update -m=“1024m” eacfa35556b6
[root@slave ~]# docker stats eacfa35556b6
3.4.容器常用命令
选项 描述
ls 列出容器
inspect 查看一个或多个容器详细信息
exec 在运行容器中执行命令
commit 创建一个新镜像来自一个容器
cp 拷贝文件/文件夹到一个容器
logs 获取一个容器的日志
port 列出或指定容器端口映射
top 显示一个容器的运行进程
stats 显示容器资源使用统计
stop/start 停止/启动一个或多个容器
rm 删除一个或多个容器
3.4.1.创建容器
启动一个容器名为web01,以nginx镜像启动的容器
[root@slave ~]# docker run -d --name web01 nginx
[root@slave ~]# docker ps
3.4.2.进入容器
[root@slave ~]# docker exec -it web01 bash
3.4.3.查看容器列表
[root@slave ~]# docker container ls
3.4.4.查看容器详细信息
[root@slave ~]# docker inspect eacfa35556b6
3.4.5.批量强制删除所有容器
[root@slave ~]# docker rm -f $(docker ps -aq)
3.4.6.拷贝文件/文件夹到一个容器
启动一个容器名为web,以nginx镜像启动的容器
[root@slave ~]# docker run -d --name web nginx
将nginx.tar文件拷贝到名为web容器下的/opt目录
[root@slave ~]# docker cp nginx.tar web:/opt
进入容器查看文件
[root@slave ~]# docker exec -it web bash
root@75017d8aa362:/# ls /opt
nginx.tar
3.4.7.把容器中的文件/文件夹拷贝出来
[root@slave ~]# docker cp web:/opt/nginx.tar /tmp
[root@slave ~]# ls /tmp/
nginx.tar
3.4.8.以现有的运行容器提交成一个或制作成一个新的镜像
创建一个用nginx镜像名为web03的容器
[root@slave ~]# docker run -itd --name web03 nginx
以名为web03的容器提交成一个名为web:30的镜像
[root@slave ~]# docker commit web03 web:03
[root@slave ~]# docker images|grep web
3.4.9.直接运行容器shell命令
[root@slave ~]# docker exec web03 ls
3.5.容器实现核心技术:Namespace
在容器化中,一台物理计算机可以运行多个不同操作系统,那就需要解决”隔离性”,彼此感知不到对方存在,有问题互不影响。
Linux内核从2.4.19版本开始引入了namespace概念,其目的是将特定的全局系统资源通过抽象方法使得namespace中进程看起来拥有自己隔离的资源。Docker就是借助这个机制实现了容器资源隔离。
Linux的Namespace机制提供了6种不同的命名空间:
IPC:隔离进程间通信
MOUNT:隔离文件系统挂载点
NET:隔离网络协议栈
PID:隔离进程信号,进程命名空间是一个父子结构,子空间对父空间可见
USER:隔离用户
UTS:隔离主机名和域名
查看命名空间
[root@slave ~]# ll /proc/$$/ns
[root@slave ~]# ls /proc/1/ns
3.6.容器实现核心技术:CGroups
Docker利用namespace实现了容器之间资源隔离,但是namespace不能对容器资源限制,比如CPU、内存。
如果某一个容器属于CPU密集型任务,那么会影响其他容器使用CPU,导致多个容器相互影响并且抢占资源。
如何对多个容器的资源使用进行限制就成了容器化的主要问题。
答:引入Control Groups(简称CGroups),限制容器资源
CGroups: 所有的任务就是运行在系统中的一个进程,而 CGroups 以某种标准将一组进程为目标进行资源分配和控制。
例如CPU、内存、带宽等,并且可以动态配置。
CGroups主要功能:
• 限制进程组使用的资源数量( Resource limitation ):可以为进程组设定资源使用上限,例如内存
• 进程组优先级控制( Prioritization ):可以为进程组分配特定CPU、磁盘IO吞吐量
• 记录进程组使用的资源数量( Accounting ):例如使用记录某个进程组使用的CPU时间
• 进程组控制( Control ):可以将进程组挂起和恢复
ls /sys/fs/cgroup/ -l 查看cgroups可控制的资源:
[root@slave ~]# ls /sys/fs/cgroup/memory/docker/
• blkio :对快设备的IO进行限制。
• cpu:限制CPU时间片的分配,与cpuacct挂载同一目录。
• cpuacct :生成cgroup中的任务占用CPU资源的报告,与cpu挂载同一目录。
• cpuset :给cgroup中的任务分配独立的CPU(多核处理器)和内存节点。 • devices :允许或者拒绝 cgroup 中的任务访问设备。 • freezer :暂停/恢复 cgroup 中的任务。 • hugetlb :限制使用的内存页数量。 • memory :对cgroup 中任务的可用内存进行限制,并自动生成资源占用报告。
• net_cls :使用等级识别符(classid)标记网络数据包,这让 Linux 流量控制程序(tc)可以识别来自特定从cgroup 任务的数据包,并进行网络限制。
• net_prio:允许基于cgroup设置网络流量的优先级。
• perf_event:允许使用perf工具来监控cgroup。 • pids:限制任务的数量。
容器实际资源限制位置:
/sys/fs/cgroup/<资源名>/docker/<容器ID>
3.7.Docker核心组件之间关系
Docker Daemon:Docker守护进程,负责与Docker Clinet交互,并管理镜像、
容器。
Containerd:是一个简单的守护进程,向上给Docker Daemon提供接口,向下
通过containerd-shim结合runC管理容器。
runC:一个命令行工具,它根据OCI标准来创建和运行容器
Namespace
命名空间,Linux内核提供的一种对进程资源隔离的机制,例如进程、网络、挂载点等资源。
CGroups
控制组,Linux内核提供的一种对进程组限制资源的机制;例如CPU、内存等资源。
UnionFS
联合文件系统,支持将不同位置的目录挂载到同一虚拟文件系统,形成一种分层的模型。
4.Docker 容器数据持久化
Docker提供三种方式将数据从宿主机挂载到容器中:
• volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。
• bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中。
• tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用
tmpfs,同时避免写入容器可写层提高性能。
4.1.数据卷(Volume)
volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式
[root@slave ~]# docker volume --help
4.1.1.查看数据卷
[root@slave ~]# docker volume ls
4.1.2.创建数据卷
创建名为ginx-vol 数据卷
[root@slave ~]# docker volume create nginx-vol
[root@slave ~]# docker volume ls
4.1.3.查看数据卷详细信息
[root@slave ~]# docker volume inspect nginx-vol
4.1.4.用数据卷(使用-v参数)创建一个容器
创建一个以nginx镜像名为nginx-test的容器,并将容器的/usr/share/nginx/html挂载到nginx-vol数据卷中
[root@slave ~]# docker run -d --name=nginx-test -v nginx-vol:/usr/share/nginx/html nginx
[root@slave ~]# docker volume inspect nginx-vol
[root@slave ~]# ls /var/lib/docker/volumes/nginx-vol/_data/
访问以Nginx镜像创建的容器
查看容器详细信息,查看容器IP
[root@slave ~]# docker inspect 8edbe659f4af
[root@slave ~]# curl 172.17.0.3
看到可以访问到nginx首页
删除容器后,查看数据还存在
[root@slave ~]#docker stop nginx-test
[root@slave ~]# docker rm nginx-test
[root@slave ~]# ls /var/lib/docker/volumes/nginx-vol/_data/
50x.html index.html
4.1.5.用数据卷(使用–mount参数)创建容器
创建一个以nginx镜像名为nginx-test的容器,并将容器的/usr/share/nginx/html挂载到nginx-vol数据卷中,src 数据卷名称,dst 容器目标目录
[root@slave ~]# docker run -d --name=nginx-test --mount src=nginx-vol,dst=/usr/share/nginx/html nginx
4.1.6.清理数据卷
[root@slave ~]#docker stop nginx-test
[root@slave ~]# docker rm nginx-test
[root@slave ~]# docker volume rm nginx-vol
注意:
- 如果没有指定卷,自动创建。
- 建议使用–mount,更通用。
4.2.挂载宿主机数据(Bind Mounts)
bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中
4.2.1.将宿主机目录挂载到容器目录(使用-v参数)
以nginx镜像后台运行一个名为nginx-test的容器,将宿主机/usr/local/nginx/挂载到容器/usr/share/nginx/html下
[root@slave ~]# docker run -itd --name=nginx-test -v /usr/local/nginx/:/usr/share/nginx/html nginx
注意:宿主机没有/usr/local/nginx/目录,执行上述命令,会自动在宿主机上创建/usr/local/nginx/目录
[root@slave ~]# ls /usr/local/nginx/
验证绑定
写入数据文件到/usr/local/nginx/中,然后获取创建容器IP,再进行访问
[root@slave ~]# echo hello > /usr/local/nginx/index.html
[root@slave ~]# docker inspect nginx-test
[root@slave ~]# curl 172.17.0.2
Hello
4.2.2.将宿主机目录挂载到容器目录(使用—mount 参数)
[root@slave ~]# mkdir /usr/local/nginx
以nginx镜像后台运行一个名为nginx-test的容器,type bind,src宿主机目录/usr/local/nginx/,容器目录/usr/share/nginx/html
[root@slave ~]# docker run -itd --name=nginx-test --mount type=bind,src=/usr/local/nginx/,dst=/usr/share/nginx/html nginx
验证绑定
写入数据文件到/usr/local/nginx/中,然后获取创建容器IP,再进行访问
[root@slave ~]# echo hello > /usr/local/nginx/index.html
[root@slave ~]# docker inspect nginx-test
[root@slave ~]# curl 172.17.0.2
清理
[root@slave ~]# docker stop nginx-test
[root@slave ~]# docker rm nginx-test
注意:
- 如果挂载目标在容器中非空目录,则该目录现有内容将被隐藏。
4.3.Volume特点
• 多个运行容器之间共享数据。
• 当容器停止或被移除时,该卷依然存在。
• 多个容器可以同时挂载相同的卷。
• 当明确删除卷时,卷才会被删除。
• 将容器的数据存储在远程主机或其他存储上
• 将数据从一台Docker主机迁移到另一台时,先停止容器,然后备份卷的目录(/var/lib/docker/volumes/)
4.4.Bind Mounts特点
• 从主机共享配置文件到容器。默认情况下,挂载主机/etc/resolv.conf到每个容器,提供DNS解析。
• 在Docker主机上的开发环境和容器之间共享源代码。例如,可以将Maven target目录挂载到容器中,每次在Docker主机
上构建Maven项目时,容器都可以访问构建的项目包。
5.Docker 容器网络
四种网络模式
• bridge
–net=bridge
默认网络,Docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中。
• host
–net=host
容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主
机的。容器除了网络,其他都是隔离的。
• none
–net=none
获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。
• container
–net=container:Name/ID
与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。
5.1.网络模式:bridge详解
bridge
–net=bridge
默认网络,Docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中。
[root@slave ~]# ip a |grep docker
可以看到一个docker0网桥
[root@slave ~]# docker network --help
5.1.1.查看当前网络
[root@slave ~]# docker network ls
5.1.2.查看网络详细信息
[root@slave ~]# docker network inspect 32a604c8eddf
5.1.3.查看网桥
[root@slave ~]# yum install bridge-utils -y
[root@slave ~]# brctl show docker0
5.1.4.创建自定义网络
[root@slave ~]# docker network create test
如果创建网络报错,重启iptables和docker
[root@slave ~]# systemctl restart iptables
[root@slave ~]# systemctl restart docker
[root@slave ~]# docker network ls
5.1.5.使用创建的自定义网络
与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信
用Nginx镜像创建一个名为nginx-test的容器并加入自定义的网络test中
[root@slave ~]# docker run -itd --name=nginx-test --network test nginx
[root@slave ~]# docker ps
5.1.5.1.查看创建容器分配的IP
[root@slave ~]# docker inspect nginx-test|grep IPAddress
5.1.5.2.测试容器使用自定义的网络
1.用busybox镜像,后台运行一个名为bs1的容器,容器网络加入到名为test网络当中
[root@slave ~]# sudo docker run -itd --name=bs1 --network test busybox
2.用busybox镜像,后台运行一个名为bs2的容器,容器网络加入到名为test网络当中
[root@slave ~]# sudo docker run -itd --name=bs2 --network test busybox
3.进入bs1或bs2,然后ping 名字为bs1或bs1的容器或主机名,可以发现能够ping通bs1或bs2
[root@slave ~]# docker exec -it bs1 sh
/ # ping bs2
PING bs2 (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.125 ms
64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.102 ms
5.2.网络模式:host、none和container详解
• host
–net=host
容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主机的。容器除了网络,其他都是隔离的。
• none
–net=none
获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。
• container
–net=container:Name/ID
与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。
5.2.1.Host
–net=host
容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主机的。容器除了网络,其他都是隔离的。
运行两个容器,一个加–net=host,一个不加–net=host,然后分别进入容器查看网卡,可以看到加了–net=host的容器有很多网卡,网络协议都是来自宿主机;没有加–net=host的网卡很少
用busybox镜像运行一个名为host1的容器,net类型为host
[root@slave ~]# docker run -itd --name=host1 --net=host busybox
用busybox镜像运行一个名为host2的容器
[root@slave ~]# docker run -itd --name=host2 busybox
[root@slave ~]# docker exec -it host1 sh
/ # ifconfig
[root@slave ~]# docker exec -it host2 sh
/ # ifconfig
5.2.1.1.查看宿主机监听的端口
[root@slave ~]# ss -antp
5.2.1.2.使用–net=host模式查看运行的容器占用宿主机端口
用nginx镜像运行一个名为host3,–net模式为host的容器
[root@slave ~]# docker run -itd --name=host3 --net=host nginx
[root@slave ~]# ss -antp|grep 80
[root@slave ~]# netstat -tulnp |grep 80
可以看到宿主机的80端口被占用
5.2.2.none
–net=none
获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。
用busybox镜像运行一个名为none,–net模式为none的容器
[root@slave ~]# docker run -itd --name=none --net=none busybox
进入容器
[root@slave ~]# docker exec -it none sh
/ # ifconfig
发现没有网卡信息
5.2.3.container
–net=container:Name/ID
与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。
用busybox镜像创建一个名为container1的容器
[root@slave ~]# docker run -itd --name=container1 busybox
用busybox镜像创建一个名为container2,并加入到container1的网络命名空间
[root@slave ~]# docker run -itd --name=container2 --net=container:container1 busybox
分别进入到容器container1和container2
[root@slave ~]# docker exec -it container1 sh
/ # ifconfig
[root@slave ~]# docker exec -it container2 sh
/ # ifconfig
发现两个IP地址一样
5.2.4.重装docker.0虚拟网卡
安装工具
[root@docekr ~]# yum install bridge-utils -y
[root@docekr ~]# systemctl stop docker
[root@docekr ~]# ip link set dev docker0 down
[root@docekr ~]# brctl delbr docker0
然后重启docker
[root@docekr ~]# systemctl restart docker
即可发现自动生成个docker0网桥
5.3.Docker网络模型与容器网络访问流程
5.3.1.Docker网络模型
veth pair:成对出现的一种虚拟网络设备,数据从一端进,从另一端出。 用于解决网络命名空间之间隔离。
docker0:网桥是一个二层网络设备,通过网桥可以将Linux支持的不同的端口连接起来,并实现类似交换机那样的多对多的通信。
5.3.2.容器网络访问原理
容器内: route是路由表的意思
首先由容器内部的 eth0(也就是veth1),发送给容器的网关 route里的 eth0(也就是宿主机的网卡 veth0)
容器外:
自定义网络的话,就会创建 一个linux网桥(br-5c710e739634),172.18.0.1 就是网关 。这个br-5c710e739634 整体就是宿主机的一个虚拟网卡。
接收 ↑发送过来的数据
5.4.容器网络实现核心技术:Iptables
表 链
filter(过滤) INPUT、OUTPUT、FORWARD
nat(地址转换) PREROUTING、POSTROUTING、OUTPUT
mangle(拆包、修改、封装) INPUT、OUTPUT、PREROUTING、POSTROUTING、OUTPUT
raw(数据状态跟踪) PREROUTING、OUTPUT
四表五链
iptables table Command Chain Parameter & Xmatch target
-t filter
nat -A
-D
-L
-F
-P
-I
-R
-n INPUT
FORWARD
OUTPUT
PREROUTING
POSTROUTING -p tcp
-s
-d
–sport
–dport
–dports
-m tcp
state
multiport -j ACCEPT
DROP
REJECT
DNAT
SNAT
操作命令
INPUT链:接收的数据包是本机(入站)时,应用此链中的规则。
OUTPUT链:本机向外发送数据包(出站)时,应用此链中的规则。
FORWARD链:需要通过防火墙中转发送给其他地址的数据包(转发)时,应用测链中的规则。
PREROUTING链:在对数据包做路由选择之前,应用此链中的规则。DNAT
POSTROUTING链:在对数据包做路由选择之后,应用此链中的规则。SNAT
查看所有iptables规则
[root@slave ~]# iptables -vnL
[root@slave ~]# iptables-save
外部访问容器
[root@slave ~]# iptables -t nat -vnL DOCKER
容器访问外部
[root@slave ~]# iptables -t nat -vnL POSTROUTING
5.5.跨主机网络:实现Docker容器多主机通信
Flannel是CoreOS维护的一个网络组件,在每个主机上运行守护进程负责维护本地路由转发,Flannel使用ETCD来存储容器网络与主机之前的关系。
其他主流容器跨主机网络方案:
• Weave
• Calico
• OpenvSwitch
主机1 内网IP:10.170.0.26 公网IP:35.220.238.143
主机2 内网IP:10.170.0.25 公网IP:35.220.197.26
5.5.1.安装etcd
在其中一台机器安装部署即可
[root@docker ~]# yum install etcd -y
[root@docker ~]# vim /etc/etcd/etcd.conf
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_CLIENT_URLS=“http://10.170.0.25:2379”
ETCD_NAME=“default”
ETCD_ADVERTISE_CLIENT_URLS=“http://10.170.0.25:2379”
[root@docker ~]# systemctl start etcd
[root@docker ~]# systemctl enable etcd
[root@docker ~]# ps -ef |grep etcd
[root@docker ~]# netstat -nutlp|grep etcd
5.5.2.flanneld安装并配置
在所有docker主机部署
[root@slave ~]#yum install flannel -y
[root@docker ~]# vim /etc/sysconfig/flanneld
FLANNEL_ETCD_ENDPOINTS=“http://10.170.0.25:2379”
FLANNEL_ETCD_PREFIX="/atomic.io/network"
5.5.3.向etcd写入子网
[root@docker ~]#etcdctl --endpoints=“http://10.170.0.25:2379” set /atomic.io/network/config ‘{ “Network”: “172.17.0.0/16”,“Backend”: {“Type”: “vxlan”} }’
获取值
[root@docker ~]#etcdctl --endpoints=“http://10.170.0.25:2379” get /atomic.io/network/config ‘{“Network”:“172.0.0.0/16”,“Backend”:{“Type”:“vxlan”}}’
启动flanneld并查看日志
[root@docker ~]# systemctl start flanneld
[root@docker ~]# tail -f /var/log/messages
5.5.4.配置Docker使用flannel生成的网络信息
[root@docker ~]# cat /run/flannel/docker
[root@docker ~]# vim /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
EnvironmentFile=/run/flannel/docker
Type=notify
ExecStart=/usr/bin/dockerd $DOCKER_NETWORK_OPTIONS
ExecReload=/bin/kill -s HUP
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
[root@docker ~]# systemctl daemon-reload
[root@docker ~]# systemctl restart docker
[root@docker ~]# ps -ef |grep docker|grep bip
可以看到引用到了/run/flannel/docker里的配置文件
5.5.5.在两台主机创建容器相互ping验证
两台主机开启iptables FORWARD
[root@docekr ~]# iptables -vnL|grep FORWARD
[root@docekr ~]# iptables -P FORWARD ACCEPT
然后先重启flanneld,再重启docker
[root@slave ~]# systemctl restart flanneld
[root@slave ~]# systemctl restart docker
再在两台主机上运行容器相互ping验证
[root@slave ~]# docker run -itd --name=slave busybox
[root@docekr ~]# docker run -itd --name=docker busybox
[root@slave ~]# docker exec -it slave sh
/ # ping 172.17.46.2
6.Dockerfile制作容器镜像
6.1.Dockerfile常用指令及使用
指令 描述
FROM 构建新镜像是基于哪个镜像
LABEL 标签
RUN 构建镜像时运行的Shell命令
COPY 拷贝文件或目录到镜像中
ADD 解压压缩包并拷贝
ENV 设置环境变量
USER 为RUN、CMD、ENTRYPOINT执行命令指定运行用户
EXPOSE 声明容器运行的服务端口
WORKDIR 为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录
CMD 运行容器时默认执行,如果有多个CMD指令,最后一个生效
ENTRYPOINT 如果与CMD一起用,CMD将作为ENTRYPOINT的默认参数,如果有多个ENTRYPOINT指令,最后一个生效
6.2.docker build构建镜像
创建一个空目录
[root@slave ~]# mkdir build
[root@slave ~]# cd build
[root@slave build]# touch a.txt
[root@slave build]# touch b.txt
[root@slave build]# tar zcvf b.tar.gz b.txt
[root@slave build]# vim Dockerfile
FROM centos:7
LABEL maintainer wenjusir
RUN yum install wget curl -y
COPY a.txt /opt
ADD b.tar.gz /opt
ENV ABC=123
EXPOSE 80
WORKDIR /usr/local
CMD [“sleep”,“36000”]
Usage: docker build [OPTIONS] PATH | URL | - [flags]
Options:
-t, --tag list # 镜像名称
-f, --file string # 指定Dockerfile文件位置
指定Dockerfile文件(-f),创建名为test的镜像,.表示有拷贝文件的路径
[root@slave build]# docker build -t test -f Dockerfile .
[root@slave build]# docker images
可以看到构建的test镜像
用创建的test镜像启动一个名为test1的容器
[root@slave build]# docker run -itd --name=test1 test
进入容器
[root@slave build]# docker exec -it test1 bash
验证构建的变量值
[root@947758378ba5 local]# echo $ABC
123
验证解压和拷贝的文件
[root@947758378ba5 local]# ls /opt/
a.txt b.txt
6.3.CMD与ENTRYPOINT区别
CMD用法:
• CMD [“executable”,“param1”,“param2”] :exec形式(首选)
• CMD [“param1”,“param2”] :作为ENTRYPOINT的默认参数
• CMD command param1 param2 :Shell形式
6.3.1.CMD用法
6.3.1.1.CMD exec形式
[root@slave build]# vim run.sh
#!/bin/bash
echo hello $1
sleep 60000
[root@slave build]# chmod +x run.sh
[root@slave build]# vim Dockerfile_CMD
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin
EXPOSE 80
CMD [“run.sh”,“wenju”]
开始构建指定文件Dockerfile_CMD,构建后的镜像名称为cmd_01
[root@slave build]# docker build -t cmd_01 -f Dockerfile_CMD .
[root@slave build]# docker images|grep cmd
用新构建的cmd_01镜像运行一个名为cmd的容器
[root@slave build]# docker run -itd --name=cmd cmd_01
查看运行的cmd容器日志,看到输出内容为 hello wenju,说明用构建的镜像运行的容器,默认运行run.sh脚本
[root@slave build]# docker logs cmd
hello wenju
注意:使用exec默认CMD命令不支持传变量
类似以下标红的地方不支持
[root@slave build]# vim Dockerfile_CMD
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin
ENV NAME=wenju
EXPOSE 80
CMD [“run.sh”,"$NAME"]
指定Dockerfile_CMD 文件构建名为test_cmd镜像
[root@slave build]# docker build -t test_cmd -f Dockerfile_CMD .
用构建的testcmd 镜像运行一个名为testcmd的容器
[root@slave build]# docker run -itd --name testcmd test_cmd
[root@slave build]# docker logs testcmd
hello $NAME
可以看到以上输出的内容没有解析到变量值,要想解析变量值,可以指定运行shell脚本
如下
[root@slave build]# vim Dockerfile_CMD
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin
ENV NAME=wenju
EXPOSE 80
CMD [“sh”,"-c","/usr/bin/run.sh $NAME"]
指定Dockerfile_CMD 文件构建名为test_cmd1镜像
[root@slave build]# docker build -t test_cmd1 -f Dockerfile_CMD .
用构建的testcmd1 镜像运行一个名为testcmd1的容器
[root@slave build]# docker run -itd --name testcmd1 test_cmd1
[root@slave build]# docker logs testcmd1
hello wenju
6.3.1.2.Shell形式
直接调用shell脚本,支持传变量
[root@slave build]# vim Dockerfile_CMD
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin
ENV NAME=wenjusir
EXPOSE 80
CMD /usr/bin/run.sh $NAME
指定Dockerfile_CMD 文件构建名为test_cmd2镜像
[root@slave build]# docker build -t test_cmd2 -f Dockerfile_CMD .
用构建的testcmd2 镜像运行一个名为testcmd2的容器
[root@slave build]# docker run -itd --name testcmd2 test_cmd2
[root@slave build]# docker logs testcmd2
hello wenjusir
6.3.1.3.覆盖默认构建的镜像CMD命令
用构建的test_cmd2 镜像运行一个名为test_fugai的容器,并直接运行run.sh脚本赋值参数sunwenju
[root@slave build]# docker run -itd --name=test_fugai test_cmd2 run.sh sunwenju
[root@slave build]# docker logs test_fugai
hello sunwenju
可以看到打印出的值是sunwenju,并不是wenjusir
6.3.2.ENTRYPOINT用法
• ENTRYPOINT [“executable”, “param1”, “param2”]
• ENTRYPOINT command param1 param2
[root@slave build]# vim Dockerfile_ENT
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin
ENV NAME=wenjusir
EXPOSE 80
ENTRYPOINT /usr/bin/run.sh $NAME
用Dockerfile_ENT文件构建一个名为test_ent镜像
[root@slave build]# docker build -t test_ent -f Dockerfile_ENT .
用构建的test_ens镜像运行一个名为ens的容器
[root@slave build]# docker run -itd --name=ens test_ent
[root@slave build]# docker logs ens
hello wenjusir
注意:ENTRYPOINT不能覆盖默认运行的命令
用构建的test_ent镜像运行一个名为test_ent的容器,并直接运行run.sh脚本赋值参数sunwenju
[root@slave ~]# docker run -itd --name=test_ent test_ent run.sh aju
[root@slave ~]# docker logs test_ent
hello wenjusir
发现还是输出wenjusir变量
6.3.3.ENTRYPOINT与CMD配合使用,CMD:作为ENTRYPOINT的默认参数
[root@slave build]# vim Dockerfile_ENT_CMD
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin/
ENV NAME=wenjusun
EXPOSE 80
ENTRYPOINT [“echo”]
CMD [“hello”,“wenju”]
用Dockerfile_ENT_CMD构建一个名为test_ent_cmd的镜像
[root@slave build]# docker build -t test_ent_cmd -f Dockerfile_ENT_CMD .
用构建的test_ent_cmd镜像启动一个名为ent_cmd的容器
[root@slave build]# docker run -itd --name=ent_cmd test_ent_cmd
[root@slave build]# docker logs ent_cmd
hello wenju
直接输出hello wenju
[root@slave build]# vim run.sh
#!/bin/bash
echo $@
sleep 60000
[root@slave build]# vim Dockerfile_ENT_CMD
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin/
ENV NAME=wenjusun
EXPOSE 80
ENTRYPOINT [“run.sh”]
CMD [“hello”,“wenju”]
用Dockerfile_ENT_CMD构建一个名为test_ent_cmd1的镜像
[root@slave build]# docker build -t test_ent_cmd1 -f Dockerfile_ENT_CMD .
用构建的test_ent_cmd1镜像启动一个名为ent_cmd1的容器
[root@slave build]# docker run -itd --name=ent_cmd1 test_ent_cmd1
[root@slave build]# docker logs ent_cmd1
hello wenju
还是直接输出hello wenju
注意:这种情况下(exec形式下[“run.sh”])可以覆盖默认的CMD
用构建的test_ent_cmd1镜像运行一个名为ent_cmd_fugai的容器,并赋值hello world
[root@slave build]# docker run -itd --name=ent_cmd_fugai test_ent_cmd1 hello world
[root@slave build]# docker logs ent_cmd_fugai
hello world
可以看到输出的内容为赋予的hello world值
非exec形式下()不支持覆盖CMD
[root@slave build]# vim Dockerfile_ENT_CMD
FROM centos:7
LABEL maintainer wenjusir
COPY run.sh /usr/bin/
ENV NAME=wenjusun
EXPOSE 80
ENTRYPOINT “run.sh”
CMD [“hello”,“wenju”]
用Dockerfile_ENT_CMD构建一个名为test_ent_cmd2的镜像
[root@slave build]# docker build -t test_ent_cmd2 -f Dockerfile_ENT_CMD .
用构建的test_ent_cmd2镜像运行一个名为ent_cmd_fugai2的容器,并赋值hello world
[root@slave build]# docker run -itd --name=ent_cmd_fugai2 test_ent_cmd2 hello wenju
[root@slave build]# docker logs ent_cmd_fugai2
可以看到输出为空
小结:
- CMD和ENTRYPOINT指令都可以用来定义运行容器时所使用的默认命令
- Dockerfile至少指定一个CMD或ENTRYPOINT
- CMD可以用作ENTRYPOINT默认参数,或者用作容器的默认命令
- docker run指定时,将会覆盖CMD
- 如果是可执行文件,希望运行时传参,应该使用ENTRYPOINT
6.4.Docker解决每次进入容器命令都要重新source /etc/profile 才能生效的问题
在~/.bashrc里面加一句source /etc/profile
[root@606b87b58111 /]# cd
[root@606b87b58111 ~]# vim ~/.bashrc
.bashrc
User specific aliases and functions
alias rm=‘rm -i’
alias cp=‘cp -i’
alias mv=‘mv -i’
Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
source /etc/profile
fi
6.5.前端项目镜像制作:openresty(nginx)
[root@slave ~]# mkdir buildfiles
[root@slave ~]# cd buildfiles
编辑配置nginx的基础配置文件
[root@slave ~]# vim nginx.conf
worker_processes 2;
worker_rlimit_nofile 102400;
worker_cpu_affinity 0000001;
pid /usr/local/openresty/nginx/logs/nginx.pid;
events {
use epoll;
worker_connections 1024;
}
http {
lua_shared_dict limit 50m;
lua_package_path “/usr/local/openresty/nginx/conf/waf/?.lua”;
init_by_lua_file “/usr/local/openresty/nginx/conf/waf/init.lua”;
access_by_lua_file “/usr/local/openresty/nginx/conf/waf/access.lua”;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
log_format main '$remote_addr -
r
e
m
o
t
e
u
s
e
r
[
remote_user [
remoteuser[time_local] “KaTeX parse error: Double superscript at position 34: … '̲status
b
o
d
y
b
y
t
e
s
s
e
n
t
"
body_bytes_sent "
bodybytessent"http_referer” ’
‘“
h
t
t
p
u
s
e
r
a
g
e
n
t
"
"
http_user_agent" "
httpuseragent""http_x_forwarded_for”’;
access_log logs/access.log main;
tcp_nopush on;
autoindex off;
server_tokens off;
gzip on;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_min_length 1k;
gzip_http_version 1.0;
gzip_types text/plain application/html application/css application/javascript application/xml;
gzip_vary on;
client_max_body_size 8m;
include vhosts/*.conf;
}
[root@slave buildfiles]# vim wenjusir.conf
upstream tomcat{
server 127.0.0.1:8080;
}
upstream php{
server 127.0.0.1:9000;
}
server {
listen 80;
server_name localhost;
access_log logs/osce.access.log main;
location / {
#rewrite ^ https:/
h
t
t
p
h
o
s
t
http_host
httphostrequest_uri? permanent;
root html;
index index.html index.htm index.php;
proxy_redirect off;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto KaTeX parse error: Expected 'EOF', got '#' at position 52: …ize 10m; #̲允许客户端请求的最大单文件字节… {
#proxy_pass http://tomcat;
root html;
expires 15d;
index index.html index.htm;
}
location ~ \.jsp(.*)$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://tomcat;
}
location ~ \.php(.*)$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED
$document_root$fastcgi_path_info;
include fastcgi_params;
}
}
[root@slave buildfiles]# vim Dockerfile-openresty
FROM centos:7
MAINTAINER sunwenju
RUN yum install -y gcc wget gcc-c++ make
openssl-devel pcre-devel gd-devel
iproute net-tools telnet wget curl unzip perl kernel-headers kernel-devel vim &&
yum clean all &&
rm -rf /var/cache/yum/*
RUN yum -y install gcc make pcre pcre-devel zlib zlib-devel openssl-devel readline-devel &&
cd &&
wget https://openresty.org/download/openresty-1.15.8.1.tar.gz &&
tar zxf openresty-1.15.8.1.tar.gz &&
cd openresty-1.15.8.1 &&
./configure --prefix=/usr/local/openresty
–with-http_stub_status_module
–with-http_ssl_module
–with-stream &&
make -j 2 && make install &&
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&
cd &&
wget https://github.com/unixhot/waf/archive/v1.0.0.tar.gz &&
tar zxf v1.0.0.tar.gz &&
cp -r waf-1.0.0/waf /usr/local/openresty/nginx/conf/
ENV PATH $PATH:/usr/local/openresty/nginx/sbin
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
WORKDIR /usr/local/openresty/nginx
EXPOSE 80 443
CMD [“nginx”, “-g”, “daemon off;”]
以Dockerfile构建一个名为openresty,版本v1的镜像,.表示上下文的目录,比如代码中有COPY复制文件到镜像中,.就表示需要复制文件所在的路径
用Dockerfile-openresty文件构建一个名为openresty:wenjusir镜像
[root@slave buildfiles]sudo docker build -t openresty:wenjusir -f Dockerfile-openresty .
用构建的openresty:wenjusir镜像创建一个名为openresty_wenjusir,并暴露容器80端口,用宿主机的80端口转发
[root@slave buildfiles]# docker run -itd --name=openresty_wenjusir -p80:80 openresty:wenjusir
[root@slave buildfiles]# docker exec -it openresty_wenjusir bash
访问宿主机80端口
也可以将宿主机的目录挂载到容器的相应目录下(数据持久化)
用构建的openresty:wenjusir的镜像运行一个名为aju的容器,并将宿主机的root目录g挂载到容器的目录下
[root@slave buildfiles]# docker run -itd --name=aju -v /root:/root -p 80:80 openresty:wenjusir
进入容器后,可以发现容器root目录下有宿主机root目录下的文件
[root@slave buildfiles]# docker exec -it aju bash
[root@4afc0bb73f4a nginx]# ls /root
boost_1_59_0.tar.gz docker-19.03.9.tgz nginx.tar
6.6.构建Tomcat镜像
[root@slave ~]# mkdir build_tomcat/
[root@slave ~]# cd build_tomcat/
[root@slave build_tomcat]# vim Dockerfile_tomcat
FROM centos:7
MAINTAINER sunwenju
RUN yum install -y gcc wget gcc-c++ make
openssl-devel pcre-devel gd-devel
iproute net-tools telnet wget curl unzip perl kernel-headers kernel-devel vim &&
yum clean all &&
rm -rf /var/cache/yum/* &&
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY jdk-8u45-linux-x64.tar.gz /root
RUN cd /root &&
tar zxf jdk-8u45-linux-x64.tar.gz &&
mv jdk1.8.0_45 /usr/local/jdk1.8
COPY apache-tomcat-8.5.31.tar.gz /root
RUN cd /root &&
tar zxf apache-tomcat-8.5.31.tar.gz &&
mv apache-tomcat-8.5.31 /usr/local/tomcat
ENV JAVA_HOME=/usr/local/jdk1.8
ENV JRE_HOME=
J
A
V
A
H
O
M
E
/
j
r
e
E
N
V
C
L
A
S
S
P
A
T
H
=
.
:
JAVA_HOME/jre ENV CLASSPATH=.:
JAVAHOME/jreENVCLASSPATH=.:JAVA_HOME/lib/dt.jar:
J
A
V
A
H
O
M
E
/
l
i
b
/
t
o
o
l
s
.
j
a
r
:
JAVA_HOME/lib/tools.jar:
JAVAHOME/lib/tools.jar:JRE_HOME/lib:
C
L
A
S
S
P
A
T
H
E
N
V
P
A
T
H
=
/
s
b
i
n
:
CLASSPATH ENV PATH=/sbin:
CLASSPATHENVPATH=/sbin:JAVA_HOME/bin:$PATH
WORKDIR /usr/local/tomcat
EXPOSE 8080
CMD ["/usr/local/tomcat/bin/catalina.sh", “run”]
用Dockerfile文件构建名为tomcat:wenjusir镜像
[root@slave build_tomcat]# docker build -t tomcat:wenjusir -f Dockerfile_tomcat .
用构建的tomcat:wenjusir镜像运行一个名为tomcat容器,并用宿主机的8080端口转发容器的8080端口
[root@slave build_tomcat]# docker run -itd --name=tomcat -p 8080:8080 tomcat:wenjusir
进入容器查看
[root@slave build_tomcat]# docker exec -it tomcat bash
[root@70174b072a5f tomcat]# netstat -ntulp
6.7.PHP项目镜像制作:PHP5.6
[root@slave ~]# mkdir build_php
[root@slave ~]# cd build_php/
[root@slave build_php]# vim Dockerfile_php
FROM centos:7
MAINTAINER www.ctnrs.com
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/*
ADD php-5.6.36.tar.gz /
RUN 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
COPY php.ini /usr/local/php/etc/
COPY php-fpm.conf /usr/local/php/etc/
WORKDIR /usr/local/php
EXPOSE 9000
CMD [“php-fpm”]
用Dockerfile_php构建php镜像,版本5.6.36; .表示上下文的目录,比如代码中有COPY复制文件到镜像中,.就表示需要复制文件所在的路径
#sudo docker build -t php:5.6.36 -f Dockerfile_php .
验证创建的PHP镜像是否有效
sudo docker run -d --name php01 php:5.6.36
#sudo docker ps -l
#sudo docker exec -it php01 bash
#[root@2821416d7282 php]# netstat -ntulp
7.docker部署LNMP网站平台
注意:这里php和mysql可以不用对外进行端口映射,只需要对外提供一个nginx流量入口
7.1.自定义网络
#sudo docker network create lnmp
7.2.创建Mysql容器
以镜像mysql:5.7,后台运行一个名为lnmp_mysql的容器,–mount方式挂载数据盘到容器中/var/lib/mysql目录,mysql的root用户名密码是123456,默认创建一个wordpress数据库,字符集是utf8
#sudo docker run -d --name lnmp_mysql --net lnmp --mount src=mysql-vol,dst=/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress mysql:5.7 --character-set-server=utf8
7.3.查看宿主机docker数据卷
#sudo ls /var/lib/docker/volumes/mysql-vol/_data
7.4.创建PHP容器
用构建的php:v1镜像,运行一个名为lnmp_php的容器,容器加入lnmp网络,挂载方式mount,创建数据卷wwwroot,挂载到容器/wwwroot目录下
#docker run -d --name lnmp_php --net lnmp --mount src=wwwroot,dst=/wwwroot php:v1
创建一个nginx主配置文件
文件内容
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.ctnrs.com;
index index.php index.html;
access_log logs/www.ctnrs.com_access.log;
error_log logs/www.ctnrs.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;
}
}
}
5、创建Nginx容器 ,容器加入lnmp网络,宿主机端口88转发容器80端口,数据挂载方式bind,将nginx.conf文件挂载到容器中
#docker run -d --name lnmp_nginx --net lnmp -p 88:80 --mount type=bind,src=$(pwd)/nginx.conf,dst=/usr/local/nginx/conf/nginx.conf --mount src=wwwroot,dst=/wwwroot nginx:v1
6、以wordpress博客为例
https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
将wordpress解压到/var/lib/docker/volumes/wwwroot/_data下
8.Docker 图形化管理
Portainer是一款开源的Dockert图像管理系统
官网:https://www.portainer.io
https://www.portainer.io/installation/按照官方文档操作即可
Portainer安装
[root@osce ~]# docker volume create portainer_data
[root@osce ~]#docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
[root@osce ~]# docker ps
待容器启动后通过IP+9000端口访问
第一次访问会提示修改密码