1.环境需求
不需要开虚拟机,只需要一个真机就行。
下载docker的安装包,可以在官网上下载 www.docker.com
yum install -y pigz-2.3.4-1.el7.x86_64.rpm docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm container-selinux-2.21-1.el7.noarch.rpm ##因为有依赖性,所以有时候需要把安装包全部下载 yum install -y *
2.docker的基础知识
(1)Docker与虚拟机比较:
kvm 完全虚拟化,修改虚拟机,不对外部机有影响,完全和真机隔离 docker 操作系统的特殊进程,部分隔离.docker(s) 比 kvm(min) 要快,也比kvm小
作为一种轻量级的虚拟化方式,Docker在运行应用上跟传统的虚拟机方式相比具有显著优势:
-Docker容器很快,启动和停止可以在秒级实现,这相比传统的虚拟机方式要快得多。
-Docker容器对系统资源需求很少,一台主机上可以同时运行数千个Docker容器。
-Docker通过类似Git的操作来方便用户获取、分发和更新应用镜像,指令简明,学习成本较低。
-Docker通过Dockerfile配置文件来支持灵活的自动化创建和部署机制,提高工作效率。
(2)docker的核心概念
镜像(Image)
-- 就是一个只读的模板。镜像是只读的,镜像中包含有需要运行的文件。例如:一个镜像可以包含一个完整的操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
仓库(Repository)
-- 是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括 时速云 、网易云 等,可以提供大陆用户更稳定快速的访问。当然,用户也可以在本地网络内创建一个私有仓库。当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。
容器(container)
-- Docker 利用容器(Container)来运行应用。容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。容器是Docker的运行组件,启动一个镜像就是一个容器,容器是一个隔离环境,多个容器之间不会相互影响,保证容器中的程序运行在一个相对安全的环境中。
Docker镜像是由文件系统叠加而成。最底端是一个文件引导系统,即bootfs。Docker用户不会与引导文件系统有直接的交互。Docker镜像的第二层是root文件系统rootfs,通常是一种或多种操作系统,例如ubuntu等。在Docker中,文件系统永远都是只读的,在每次修改时,都是进行拷贝叠加从而形成最终的文件系统。Docker称这样的文件为镜像。一个镜像可以迭代在另一个镜像的顶部。位于下方的镜像称之为父镜像,最底层的镜像称之为基础镜像。最后,当从一个镜像启动容器时,Docker会在最顶层加载一个读写文件系统作为容器。Docker的这种机制我们称之为写时复制。
对docker的启动需要容器,需要镜像,仓库。
仓库(私有和公共)registry——>镜像images——>容器container——>提交之后——>保存到仓库registry里
(3)什么是Docker?
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。Docker容器的运行不需要额外的虚拟化管理程序(Virtual Machine Manager,VMM,以及Hypervisor)支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。
(4)一个完整的Docker具有什么?
一个完整的Docker有以下几个部分组成:
Docker Client 客户端
Docker Daemon 守护进程
Docker Image 镜像
Docker Container 容器
Docker是CS架构,主要有两个概念:
- Docker daemon: 运行在宿主机上,Docker守护进程,用户通过Docker client(Docker命令)与Docker daemon交互
- Docker client: Docker 命令行工具,是用户使用Docker的主要方式,Docker client与Docker daemon通信并将结果返回给用户,Docker client也可以通过socket或者RESTful api访问远程的Docker daemon
3.docker对于game2048的部署
下载一个game2048.tar
还有所需要的镜像 rhel7
docker load -i game2048.tar ##导入game2048的镜像
docker images ##列出了所有顶层(top-level)镜像。查看宿主机上的镜像,Docker镜像保存在/var/lib/docker目录下。
ip addr ##在docker开启以后,会自动生成docker0的ip
docker run -d --name vm1 game2048 ##生成一个vm1的容器 -d打入后台 利用game2048镜像
docker ps ##查看添加的容器
docker inspect vm1 ##查看添加的容器vm1 会自动的给Docker分配ip,如下图:
注意:docker inspect <container-id> or <image-id>:docker inspect命令会提取出容器或者镜像最顶层的元数据
测试:在网页上输入 172.17.0.2 就会出来game2048的游戏界面
4.docker创建容器的命令
导入镜像:
docker load -i ubuntu.tar
docker load -i rhel7.tar
创建容器:
docker run -d --name vm1 rhel7 ##创建vm1容器,利用rhel7的镜像
docker run -it --name vm2 ubuntu ## -it 具有交互界面
docker run -it --name vm3 rhel7 bash ##必须加bash才会出现交互界面
注意:docker run <image-id>: docker run就是docker create和docker start两个命令的组合,支持参数也是一致的,如果指定容器名字时,容器已经存在会报错,可以增加 --rm 参数实现容器退出时自动删除。
查看容器: docker ps 查看创建的全部的容器:docker ps -a
====================================================================================
注意:虚拟机的ip是顺序分配的。刚开始的docker启动之后,会自动添加一个docker0:172.17.0.1,在之后创建的容器,会按照创建的顺序依次分配ip,比如:vm1的game2048的ip就是 172.17.0.2 ,到现在创建的vm2的ip就会分配为 172.17.0.3
====================================================================================
5.docker容器的交互界面的退出及容器(镜像)的删除
(1)退出
ctrl+P+Q ##退出进程但是不停止,在ps的时候可以看到进程信息
ctrl+D ##直接退出,在ps的时候看不见正在运行的进程
(2)删除
<1>容器的删除
docker rm vm1 ##有时容器正在运行,就会出现删除不了的情况
docker rm -f vm1 ##出现删除不了的情况时,需要 -f 强制删除
docker container prune ##将所有已经暂停的容器全部删除
docker rm ‘docker ps -aq‘
<2>镜像的删除
docker rmi 镜像的名称
6.容器退出后的链接
情况一:ctrl+P+Q 退出
docker attach vm2
ls
touch file{1..20}
情况二:ctrl+D 退出 这个直接将容器关闭了,而不是打入后台运行,所以 attach 连接不上
docker attach vm2 ##会显示链接失败,vm2是一个停止运行的容器,所以需要先开启
docker start vm2 ##应为是全部的关闭,所以需要先开启,在连接
docker attach vm2
ls ##刚才建立的文件依旧存在
====================================================================================
注意:一旦容器被删除,再创建一个名字一样的容器是没用的,容器内的建立的文件已经不存在了,如果需要保存的话,可以将容器commit保存一下
docker commit <container-id>: 将容器的可读写层转换为一个只读层,这样就把一个容器转换成了不可变的镜像。
====================================================================================
退出以后保存,转化成新的镜像:
docker commit vm2 ubuntu:v1
docker history ubuntu
docker history ubuntu:v1
可以看出两个镜像的不同,v1多了一层,就是新建的文件,保存下来了,这样用这个新的镜像,创建出来的容器都会含有新建的文件的这一层,如果不想要这一层文件,可以将 v1 这个镜像删除。
转换成新的镜像之后:
docker rm vm2
docker run -it --name vm2 ubuntu:v1
ls ##文件层存在
7.docker的基础命令
docker images ##列出了所有顶层(top-level)镜像。
docker load -i ##导入镜像
docker run --name ##创建一个容器并运行
docker ps ##显示当前的并且正在运行的容器
docker ps -a ##查看存在的但是没有运行的容器
docker run -it(交互式) --name ##交互式的,bash是用来交互的解释器
docker rm ##删除容器,但是在线情况下的容器不能删除,但是-f可以强制
注意:镜像当中的是只读的,容器是在镜像的基础之上的写入自己独有的命令
docker rmi ##删除镜像
docker history game2048:lastest ##查看历史
docker -d ##打入后台
docker inspect vm1
docker commit vm ubuntu:v1 ##提交,会生成新的镜像,并命名为v1
docker configs ##是用来的管理的
docker container ##是管理的子命令,和上层的一样,专门针对容器操作的
docker cp /etc/passwd vm2:/tmp ##物理机和容器之间复制文件
docker exec ##不需要登陆,在外部直接运行一些指令
docker export ##针对对象是容器,输出,转换成镜像文件,共享镜像
docker logs ##查看,记录在容器内执行的任何操作
docker network ##显示容器网络
port docker -p ##端口映射 8080:80 物理机的:容器的
docker top ##显示容器内的进程
8.docker的exec的示例:
如果不知道docker exec的用法,可以使用docker exec --help 来查看。
docker cp /etc/passwd vm2:/tmp ## 物理机和容器之间复制文件
docker attach vm2
ls
cd /tmp
ls ##就可以看到cp进来的文件
docker exec vm2 ls /passwd ##直接就可以查看容器内的文件,不需要建立连接。
docker exec vm2 rm /passwd ##直接就可以删除容器内的文件 ,不需要建立连接。
9.docker的port的示例:
docker run -d --name vm1 -p 8080:80 game2048
## -p 进行端口映射,真机的8080端口,映射到容器的80端口 Docker的端口映射是由 iptables 来实现的
docker port vm1 ##用来查看端口映射
测试:在网页上输入 172.25.254.9:8080 会出现game2048的游戏界面
10.使用官方的镜像加速器
为什么要使用镜像加速器?我们使用Docker的第一步,应该是获取一个官方的镜像,例如mysql、wordpress,基于这些基础镜像我们可以开发自己个性化的应用。我们可以使用Docker命令行工具来下载官方镜像。但是因为网络原因,我们下载一个300M的镜像需要很长的时间,甚至下载失败。因为这个原因,阿里云容器Hub服务提供了官方的镜像站点加速官方镜像的下载速度
在网页上:www.aliyun.com 登陆注册 —> 管理控制台 -> 镜像库 -> 镜像加速器
cd /etc/docker/
vim daemon.json
{
"registry-mirrors": ["https://vo5twm71.mirror.aliyuncs.com"]
}
systemctl daemon-reload
systemctl restart docker
systemctl status docker
11.docker中的nginx的部署
(1)导入镜像并创建新的容器vm1
docker search nginx ##在官方的仓库中下载相应需要寻找的镜像
docker pull nginx ##将找到的镜像拉取到本地的物理机上,物理机上的某一个特定的目录下面,docker的镜像的目录,可以访问的。
docker run -d --name vm1 -p 8080:80 nginx ##创建一个新的容器vm1和物理机的8080端口相映射。
docker ps ##命令查看创建的新的容器vm1 ps查看活跃的容器 ps -a查看全部的容器
59b9de50f4b5 nginx "nginx -g 'daemon of…" 3 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp vm1
docker port vm1 ##查看vm1的端口的信息
80/tcp -> 0.0.0.0:8080
测试:在网页上输入 172.25.254.9:8080
(2)nginx的发布页面的修改:
方法一:可以在物理机上的某一个目录下,创建一个新的发布文件,发送到docker的默认的发布目录中
cd /tmp ##在物理机中
mkdir docker
cd docker/
vim index.html
server
docker cp index.html vm1:/usr/share/nginx/html
测试:在网页上输入 172.25.254.9:8080 ##注意要清除网页的缓存
方法二:直接挂载,将物理机的目录挂载在docker容器的默认的发布目录下
cd /tmp/docker
mkdir web
mv index.html web/
docker rm vm1
docker run -d --name vm1 -p 8080:80 -v /tmp/docker/web/:/usr/share/nginx/html nginx ##将主机的目录/tmp/docker/web/作为容器的数据卷挂载到容器中,使宿主机和容器之间可以共享一个目录。以后就可以直接修改主机的目录,容器的发布目录也会跟着改变
12.数据卷管理
数据卷(Data Volumes)是一个可供容器使用的特殊目录,它提供了很多有用的特性:对数据卷的修改会立马生效,数据卷会一直存在,直到没有容器使用,数据卷可以被多个容器使用,数据卷类似于Linux的mount。实质是在当前机器映射了一个目录到容器内部。
数据卷容器(Data Volume Dontainers)其实就是一个普通的容器,只是我们专门用它提供数据卷供其它容器挂载使用。使用--volumes-from指定数据卷容器。多个--volumes-from将挂载多个数据卷容器。
注意:使用--volumes-from参数所挂载的数据卷容器本身并不需要保持运行状态。如果删除了挂载的容器,数据卷并不会被自动删除,如果要删除一个数据卷,必需使用docker rm -v命令来指定同时删除管联的容器。
docker run 在创建容器时使用 -v 参数可以挂载一个或多个数据卷到当前运行的容器中,-v的作用是将宿主机上的目录作为容器的数据卷挂载到容器中,使宿主机和容器之间可以共
享一个目录。
(1)挂载数据卷到新创建的容器上:
docker run -it --name vm1 -v /tmp/data1:/data1 -v /tmp/data2:/data2 rhel7 /bin/bash
##-v 参数可以重复使用,挂载多个数据卷到容器中,冒号前面的是宿主机的目录(本地目录不存在 docker 会自动创建),冒号后面的是容器中的挂载目录。docker commit 时卷的数据不会被保存。
(2)默认挂载可以读写数据卷,也可以只读挂载:
docker run -it --name westos2 -v /tmp/data2:/data2:ro rhel7 /bin/bash
(3)挂载宿主机文件:
docker run -it --name vm2 -v /etc/yum.repos.d/rhel-dvd.repo:/etc/yum.repos.d/rhel-dvd.repo:ro rhel7 /bin/bash
(4)数据卷容器:
docker create --name data -v /tmp/sharedata:/sharedata rhel7 /bin/true
docker run -it --name vm1 --volumes-from data rhel7 /bin/bash
docker run -it --name vm2 --volumes-from data rhel7 /bin/bash
示例1:数据卷的挂载
docker ps ##删除没有用的容器
docker run -it --name vm1 -v /tmp/docker/dvd.repo:/etc/yum.repos.d/dvd.repo:ro -v /tmp/docker/data1:/data1 -v /tmp/docker/data2:/data2 rhel7
##创建一个叫vm1的容器,将主机的dvd文件挂载到容器内的yum源的默认目录下,再挂载两个目录到容器内,ro代表只读挂载。
bash-4.2# ls ##会显示出挂载的文件或是目录
bash-4.2# cd data1 ##进入到挂载的目录下,创建文件,文件是写入到主机的
bash-4.2# touch file1
bash-4.2# cd ..
bash-4.2# cd data2 ##进入到挂载的目录下,创建文件,文件是写入到主机的
bash-4.2# touch file2
bash-4.2# cd /etc/yum.repos.d/ ##只读挂载了真机的yum源文件
bash-4.2# ls
bash-4.2# cat dvd.repo ##只读挂载,因此可以 cat
bash-4.2# rm -fr dvd.repo ##但是,执行其他操作就会报错
rm: cannot remove 'dvd.repo': Device or resource busy
bash-4.2# yum repolist ##因为挂载了yum源,所以可以下载
bash-4.2# yum install -y httpd ##下载是可以的
bash-4.2# /usr/sbin/httpd ##开启httpd服务
bash-4.2# netstat -antlp ##查看端口是否被开启
bash-4.2# cd /var/www/html/
bash-4.2# echo wf > index.html
测试:在网页上输入 172.17.0.2 ##注意要清除网页的缓存
示例2:数据卷容器的创建和使用
docker create --name datavol -v /tmp/docker/dvd.repo:/etc/yum.repos.d/dvd.repo:ro -v /tmp/docker/data1:/data1 -v /tmp/docker/data2:/data2 rhel7 bash
docker run -it --volumes-from datavol --name vm1 rhel7 bash
docker run -it --volumes-from datavol --name vm2 rhel7 bash
docker run -it --volumes-from datavol --name vm3 rhel7 bash
注意:进入到容器内之后,容器内的数据是相同的
13.容器网络模型
容器有四种网络模型:bridge 桥接模式、host 模式、container 模式和 none 模式
---桥接模式:该模式下 Docker Container 不具有一个公有 IP,即和宿主机的 eth0 不处于同一个网段。导致的结果是宿主机以外的世界不能直接和容器进行通信。
桥接的实现步骤如下:
(1) Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方。
(2) Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0;
(3) Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0。如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收,实现宿主机到Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。
示例:
docker run -it --name vm1 ubuntu ##默认的网络模型是桥接模式,这种模式下,自动按顺序分配ip
---host模式:容器和物理机共享一个网络,如何分辨访问的是容器还是物理机?开启的端口不一样,网络资源只有一份。
host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。当然,有这样的方便,肯定会损失部分其他的特性,最明显的是 Docker Container 网络环境隔离性的弱化,即容器不再拥有隔离、独立的网络栈。另外,使用 host 模式的 Docker Container 虽然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用;另外,容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网络模式容器的端口映射。
示例:
docker run -it --name vm2 --net host ubuntu ##设置网络模式为host型,因此ip addr看到的网络信息和主机的一样,都含有docker0
---自定义(container)模式:和定义的容器是网络共享的
Container 网络模式:
(1) 查找 other container(即需要被共享网络环境的容器)的网络 namespace;
(2) 将新创建的 Docker Container(也是需要共享其他网络的容器)的 namespace,使用other container 的 namespace。
Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。但是需要注意的是,它并没有改善容器与宿主机以外世界通信的情况
示例:
docker run -it --name vm3 --net container:vm1 ubuntu ##设置网络模式为container型,vm1和vm3的ip 是一样的
--none模式:网络环境为 none,即不为 Docker Container 任何的网络环境。一旦 Docker Container 采用了 none 网络模式,那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。可以说 none 模式为 Docker Container 做了极少的网络设定,但是俗话说得好“少即是多”,在没有网络配置的情况下,作为 Docker 开发者,才能在这基础做其他无限多可能的网络定制开发。在 none 网络模式下可以分配固定的 ip
示例: 给容器添加固定的网络地址
docker run -it --name vm4 --net none ubuntu ##设置网络模式为none型,没有ip
ip netns list ##使用方法 ip netns help 查看所有 network namespace
docker inspect vm4 | grep Pid
cd /proc/5065
cd ns/
ls
pwd
ln -s /proc/5065/ns/net /var/run/netns/5065
ip link add name veth0 type veth peer name veth1
ip addr ##可以看到创建了一对虚拟网络接口设备
ip link set up veth0
ip link set up veth1 ##将两个接口设备开启
ip addr ##查看端口是否开启
brctl addif docker0 veth0 ##将虚拟网络接口设备的一个与docker0链接
ip netns list
ip link set veth1 netns 5065 ##将虚拟网络接口设备的另一个与容器链接
ip netns exec 5065 ip link set veth1 name eht0
ip netns exec 5065 ip addr add 172.17.0.100 ##给容器添加ip
注意:docker attach vm4 -> ip add -> ip addr add 172.17.0.100/24 dev veth1 ##这样添加ip是不行的,不被允许的
ip netns exec 5065 ip route add default via 172.17.0.1 ##添加网关
14.docker安全
设置特权级运行的容器:--privileged=true ##这个一开启就相当于是root用户
docker run -it --name vm1 ubuntu
root@63733880d3f0:/# ip addr
root@63733880d3f0:/# ip addr del 172.17.0.2/16 dev eth0
RTNETLINK answers: Operation not permitted
上面的权限被限制了,是因为:
docker inspect -f {{.HostConfig.Privileged}} vm1
false ##默认的权限是关闭的,也就是说,默认的是普通用户的身份
因此,可以将这个设置为true,就运行了root用户的身份,就可以删除
docker run -it --name vm2 --privileged=true ubuntu ##创建用户的时候,开启权限
root@a8dc66fa5137:/# ip addr
root@a8dc66fa5137:/# ip addr del 172.17.0.2/16 dev eth0
root@a8dc66fa5137:/# ip addr ##成功删除
15.容器间互联:
--link 参数可以在不映射端口的前提下为两个容器间建立安全连接, --link 参数可以连接一个或多个容器到将要创建的容器。
--link 参数的格式为 --link name:alias,其中 name 是要链接的容器的名称,alias 是这个连接的别名。
16.Dockerfile的创建
=====================================================================================
Dockerfile文件语法
(1)FROM(指定基础image)
构建指令,必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。镜像可以指定标签。 格式:FROM <image>:<tag>
(2)RUN
构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了ubuntu,那么软件管理部分只能使用ubuntu的命令。RUN指令可以有多条,每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时,可以用\来换行。
(3)CMD(设置容器启动时执行的操作)
设置指令,用于容器启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。
注意:
1) CMD运行在镜像构建之后,容器启动的时候;
2) CMD只执行最后一条
3) CMD可以被用户指定的命令覆盖
(4)EXPOSE(指定容器需要映射到宿主机器的端口)
设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。格式为:
例如:
EXPOSE 80 443 11211 ##告诉Docker服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过-P,Docker主机会自动分配一个端口转发到指定的端口;使用-p,则可以具体指定哪个本地端口映射过来。
(5)ENV(用于设置环境变量)
构建指令,在image中设置一个环境变量。格式:
ENV <key> <value>
设置了后,后续的RUN命令都可以使用,容器启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。
(6)ADD(从src复制文件到容器的dest路径)
构建指令,所有拷贝到容器中的文件和文件夹权限为0755,uid和gid为0。格式为:
ADD <src> <dest> ## <src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;<dest>是容器中的绝对路径。该命令将复制指定的<src>到容器中的<dest>。其中<src>可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(自动解压为目录)。
# 如果是一个目录,那么会将该目录下的所有文件添加到容器中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入<dest>;如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。
(7)COPY
格式为 COPY <src> <dest>
复制本地主机的<src>(为Dockerfile所在目录的相对路径,文件或目录)为容器中的<dest>。目标路径不存在时,会自动创建。
当使用本地目录为源目录时,推荐使用COPY。
(8)VOLUME(指定挂载点))
设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。格式: VOLUME ["<mountpoint>"]
示例:
FROM base
VOLUME ["/tmp/data"]
运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共享的/tmp/data目录,那么可以运行下面的命令启动一个容器:
docker run -t -i -rm -volumes-from container1 image2 bash ##container1为第一个容器的ID,image2为第二个容器运行image的名字。
(9)WORKDIR(切换目录)
设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。格式:
WORKDIR /path/to/workdir
示例:
在 /p1/p2 下执行 vim a.txt
WORKDIR /p1
WORKDIR p2
RUN vim a.txt
====================================================================================
(1)httpd的镜像的创建
cd /tmp/docker
vim Dockerfile
FROM rhel7 ##基础镜像
ENV HOSTNAME server1
EXPOSE 80
COPY dvd.repo /etc/yum.repos.d/dvd.repo ##仓库没有yum源,将真机的yum源cp到容器里
RUN rpmdb --rebuilddb && yum install -y httpd && yum clean all
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
docker build -t rhel7:v1 . ##创建镜像 rhel7:v1
docker images
docker run -d --name vm1 rhel7:v1
docker inspect vm1
测试:在网页页面上输入:172.17.0.2
(2)nginx的原码编译的镜像的创建
cd /tmp/docker
vim Dockerfile
FROM rhel7
EXPOSE 80
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.14.0.tar.gz /mnt
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel make zlib-devel
RUN yum clean all
WORKDIR /mnt/nginx-1.14.0
RUN ./configure --prefix=/usr/local/nginx --with-threads --with-file-aio --with-http_stub_status_module
RUN make
RUN make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t rhel7:v2 .
docker run -d --name vm2 rhel7:v2
docker inspect vm2
测试:在网页页面上输入:172.17.0.2 (会出现nginx的欢迎界面)
(3)nginx:v1的创建
docker load -i distroless-java.tar
docker images
cd /tmp/docker
vim Dockerfile
FROM nginx:1.14.1 as base
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG Asia/Shanghai
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base
COPY --from=base /opt /
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
docker build -t nginx:v1 .
17.缩减镜像空间
镜像每一层都有自己的ip,每一层都需要占用一定的空间
优化:--删除内部的缓存;尽量减少层数;
--多级的RUN可以把多个RUN放在一层;
--装了很多的包,安装完成后,并没有删除;
--可以在一台真机上安装好,再另一个新的仓库里cp到新的仓库里;
--基础镜像的缩减;
18.docker私有仓库的搭建
私有仓库的搭建:
(1)下载镜像:docker search registry
docker pull registry ##或者本机上已经存在registry.tar包,使用docker load -i registry.tar下载
docker images ##查看下载后的镜像
(2)镜像更名:
docker tag registry:2.3.1 registry:latest
3运行docker容器:
mkdir /tmp/docker/registry ##创建数据存储的文件夹,将真机的/tmp/registry目录映射到/mnt/docker/registry
docker run -d --name registry -p 5000:5000 -v /tmp/docker/registry:/var/lib/registry registry:2.3.1 ##启动容器,设定端口5000 ,然后映射文件夹,-v <宿主机目录>:<容器目录>
(4)推送镜像到仓库:
docker tag nginx localhost:5000/nginx
(5)推送到本地的仓库上:
docker push localhost:5000/nginx ##此时可使用tree . 命令查看当前推送结构
(6)开放注册https协议:
vim /etc/docker/daemon.json
"insecure-registries": ["172.25.254.9:5000"]
(7)重启服务:systemctl restart docker
(8)重启仓库:docker start registry ##此时使用docker ps可以查看到仓库
(9)更名:
docker tag rhel7 172.25.254.9:5000/rhel7
(10)推送到本地的仓库上:
docker push 172.25.254.9:5000/rhel7
(11)查看详细信息:
docker inspect registry:2.3.1 ##可以看到他的主配置文件在/etc/docker/registry/config.yml
添加证书:
(1)生成证书:
openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt ##注意主机名必须写成xx.xx的形式,同时在本机上要做好/etc/hosts的本地解析
(2)删除刚才建好的仓库:
docker rm -f registry
(3)建立仓库:
docker run -d --name registry -v `pwd`/certs:/certs -v /tmp/docker/registry:/var/lib/registry -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key -p 443:443 registry:2.3.1 ##其中:-e REGISTRY_HTTP_ADDR=0.0.0.0:443 编辑容器内部参数 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt 使用证书 -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key 私钥 -p 443:443 端口映射
(4)添加认证:
mkdir /etc/docker/certs.d
mkdir /etc/docker/certs.d/westos.org
cd /etc/docker/certs.d/westos.org
cp /tmp/docker/certs/domain.crt ca.crt
(5)更名:
docker tag ubuntu:latest westos.org/ubuntu
(6)推送到本地的仓库上:
docker push westos.org/ubuntu
添加用户认证:
(1)添加用户:
docker run --rm --entrypoint htpasswd registry:2.3.1 -Bbn admin westos > auth/htpasswd
追加用户:
docker run --rm --entrypoint htpasswd registry:2.3.1 -Bbn wf westos >> auth/htpasswd
(2)删除刚才建好的仓库:
docker rm -f registry
(3)建立仓库:
docker run -d --name registry -v `pwd`/certs:/certs -v /tmp/docker/registry:/var/lib/registry -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key -v `pwd`/auth:/auth -e REGISTRY_AUTH=htpasswd -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd -p 443:443 registry:2.3.1
(4)更名:
docker tag game2048:latest westos.org/
(5)用户登陆:
docker login westos.org ##一定要先成功登陆以后才能推送
(6)推送到本地的仓库上:
docker push westos.org/game2048
19.docker-compose
Docker Compose 是一个用来创建和运行多容器应用的工具。使用 Compose首先需要编写Compose 文件来描述多个容器服务以及之间的关联,然后通过命令根据配置启动所有的容器。Dockerfile 可以定义一个容器,而一个 Compose 的模板文件(YAML 格式)可以定义一个包含多个相互关联容器的应用。
docker load -i haproxy.tar
cp docker-compose-Linux-x86_64-1.22.0 /usr/local/bin/docker-compose
chmod +x/usr/local/bin/docker-compose
cd /tmp/docker/
mkdir compose
cd compose/
vim docker-compose.yml
mkdir haproxy
cd haproxy/
vim haproxy.cfg
docker-compose up ##可能会启动不了,报错显示,端口被占用
systemctl stop httpd ##可能是http服务占用了80端口,将服务关闭
docker-compose up ##再次开启就会起来
重起一个shell:
docker ps ##就可以看到compose运行
cd /tmp/docker/web
vim index.html
wf
docker cp index.html compose_web1_1:/usr/share/html
vim index.html
westos
docker cp index.html compose_web2_1:/usr/share/html
测试: 在网页上就可以看到负载均衡的结果
注意:如果要开启/关闭 compose ,必须要在compose的目录下,因为它会要读取yml文件,不在目录下开启/关闭,会发生报错