部署非常慢、成本高、资源浪费、难于迁移和扩展、可能会被限定硬件厂商
一个物理机可以部署多个app,每个app独立运行在一个vm里,现如今虚拟主机、web服务器、数据库、对象存储等等各种服务都可以同个各种各样的云平台来完成
是一种资源管理技术,是将计算机的各种实体资源(CPU、内存、磁盘空间、网络适配等),予以抽象、转换后呈现出来并可供分割、组合为一个或多个电脑配置环境
镜像是只读的,就是拉到本地并没有运行
容器是可写的,已经运行并且能进入到容器内
docker容器与传统虚拟化的对比
特性 | 容器 | 虚拟机 |
---|---|---|
启动时间 | 秒级 | 分钟级 |
资源损耗 | 几乎无 | 至少损耗50%左右(系统占用) |
硬盘空间 | MB | GB |
系统支持 | 上千个 | 几十个 |
隔离性 | 资源限制 | 完全隔离 |
性能 | 接近原生 | 弱于 |
对(DevOps)人员来说,最希望的就是项目环境一次创建或配置,可以在任意地方正常运行。开发者可以使用一个标准的镜像来构建一套项目开发容器,代码开发完成之后,运维人员可以直接此容器打包迁移。Docker可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。Docker将会大量地节约开发、测试、部署的时间。
Docker容器的运行不需要额外的管理系统支持,它是内核级的虚拟化,并且容器调用的是宿主机的bin和lib。因此可以实现更高的性能和效率。
Docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个平台。
使用 Docker只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理
Docker是基于google公司推出的golang语言开发而来,基于linux系统内核的Cgroups、NmaeSpace,以及Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术
对进程进行封装隔离,属于操作系统层面的虚拟化技术
利用docker可以实现开发,测试,生产环境的部署一致性,极大的减少运维成本
Image镜像,构建容器(我们讲应用程序所需要的环境,打包为镜像文件)
Container,容器(应用程序跑在容器中)
镜像仓库(dockerhub)保存镜像文件,提供上传,下载镜像,作用好比github
Dockerfile,将你部署项目的操作,写成一个部署脚本,这就是dockerfile,且该脚本还能够构建出镜像文件
获取镜像,如docker pull centos,从镜像仓库拉取
使用镜像创建容器
分配文件系统,挂载一个读写层,在读写层加载镜像
分配网络/网桥接口,创建一个网络接口,让容器和宿主机通信
容器获取ip地址
执行容器命令,如/bin/bash
反馈容器启动结果
镜像:image
容器:container
仓库:Repository
docker必须在centos7平台,内核版本不低于3.10
uname -r 查看本主机内核
环境初始化 关闭防火墙、安全机制
cat <<EOF > /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.ip_forward=1
EOF
加载修改内核的参数配置文件
modprobe br_netfilter
sysctl -p /etc/sysctl.d/docker.conf
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum -y install yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce
systemctl start docker
systemctl enable docker
清理缓存创建新的缓存
yum clean all && yum makecache
安装yum -y install docker-ce
卸载yum -y remove docker-版本号
mkdir /etc/docker #如果没有启动docker需要创建此目录
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://8xpkSwnt.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload ##重新加载配置文件
systemctl start docker ##启动docker
systemctl enable docker ##设为开机自启动
//查看是否设置为开机自启动systemctl is-enabled 服务名称
[root@localhost ~]# systemctl is-enabled docker
enabled
\##查看docker有没有启动成功
ps -ef |grep docker 或 docker version
//启动
systemctl start docker
//停止
systemctl stop docker
//开机自启
systemctl enable docker
//重启docker
systemctl restart docker
//查看状态
systemctl status docker
esc键+. #可以调用上一条命令
ctrl+insert #复制
shift+insert #粘贴
ctrl+r #输入某个单词搜索历史命令
ctrl+p #返回上一次输入命令字符
//docker 帮助命令
docker --help
//如果忘记某一个命令怎么使用,有哪些参数
eg:docker pull --help
//查看docker内组件及版本信息
docker version
//查看docker版本信息
docker --version
//显示docker的系统信息,包括镜像和容器的数量
docker info
docker images 或docker image ls
选项:
-q 或 --quit #只显示镜像的id
-qa #显示所有镜像的id
--format #格式化显示镜像 例::docker images --format "{{.ID}}--{{.Repository}}"
##参数详解:
REPOSITORY:镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像的id
CREATED:镜像的创建时间
SIZE:镜像的大小
//打标签(原有的容器删除,标签还能继续使用)
docker tag 镜像名 自定义标签名
//查看一个镜像具体信息加inspect参数即可
docker image inspect 镜像id
//查找镜像,查到之后一般选择第一个,是官方认证
docker search nginx ##nginx为镜像名
//拉取镜像,如果不加版本号会自动拉取最新版本,如果本地没有会直接拉取
docker pull nginx:1.22.1
##查看容器的详细信息,用于高级的调试
docker container inspect 容器id/容器名称
##查看容器内的所有日志信息
docker logs 容器id/容器名称
docker logs -f --tail=要查看末尾多少行 默认all 容器ID
-f 实时刷新
##查看容器端口转发情况
docker port 容器id/容器名称
##登录方式
docker run -it 自定义起的那个名 bash
##查看容器内进程信息
docker top 容器id
##动态查看容器内资源信息
docker stats 容器id
//运行镜像
docker run -d -p 80:80 nginx
//选项
-d ##后台运行容器
-p ##宿主机端口:容器内端口(端口映射)/tcp (tcp指定远程传输协议) 当访问宿主机端口也就是访问到了容器内的端口,启动后会返回一个容器id
--expose:接受指定范围作为参数比如:--expose=2000~3000
-P ##大P 随机指定端口
-it ##使用交互方式运行, 进入容器查看内容
--rm ##运行测试一个容器,当挂掉之后不会有记录自动删除
--name 自己起的名 镜像名 ##给容器起个名字
//查看有哪些容器在运行
docker ps ##查看启动的容器
//参数详解:
CONTAINER ID 镜像id号
IMAGE 依赖于哪个镜像运行
COMMANE 里面执行的命令
CREATED 创建时间
STATUS 状态
PORTS 端口映射
NAMES 名称
//选项
-a 列出当前正在运行的容器+历史运行过的容器
-n=?显示最近创建的?容器
-q 显示运行容器的编号(id)
-l 只显示最近启动的一个容器
-v 宿主机目录:容器里边的路径 数据持久化
//运行centos发行版,运行容器且进入容器内:
## -it交换式命令操作 bash进入容器后执行的命令 --restart=always 容器出现问题后一致重启
docker run -itd -p id号 /bin/bash
eg:docker run -itd -p 9000:8080 --name tomcat01 tomcat:8.0.52 /bin/bash
eg:docker run -d --restart=always -p 80:80 -v /opt/data:/tmp/opt/data nginx
##查看是否切换到容器内的发行版本(centos)
cat /etc/redhat-releas
##查看是否切换到容器内的发行版本(ubuntu)
cat /etc/lsb-release
##查看是否切换到容器内的发行版本(opensuse)suse为花钱的
cat /etc/SuSE-release
//有的时候呢,我们需要对一个镜像进行分类或者版本迭代操作
docker tag 源镜像名 新的镜像名
eg:docker tag nginx nginx01
#源镜像删除,打包的镜像不会被删除,还可以使用
docker rename 容器ID/容器名 新容器名
##进入到正在运行的容器内 #/bin/bash使用的解释器
docker exec -it 镜像id /bin/bash
docker attch 容器名/容器id
#比如默认运行的centos镜像,不提供vim运行该容器后,在容器内安装vim,然后提交该镜像,在导出镜像为压缩文件,可以发给其他人用
docker connit
#制作新的容器,运行基础的centos,在容器内安装vim然后提交新的运行镜像,退出,然后容器就会挂掉,在运行出的容器,就默认携带vim了
docker commit 安装过vim的容器的id 自定义起个名
-m 说明信息
-a 作者信息
-p 生成过程中停止容器的运行
//创建容器但不运行
docker create
//停止运行容器
docker stop 镜像id/镜像名
//启动运行容器
docker start 镜像id/镜像名
//重新启动运行容器
docker restart 镜像id/镜像名
//kill杀掉容器,停止运行
docker kill 容器id/容器名
//启动容器时,可加此参数 --restart=always #表示该容器随docker服务启动而启动,当服务挂掉docker也会尝试去启动
#如果容器已经启动但是没有加此参数,可以修改其启动配置即可
docker update #更新已经在运行的容器命令参数
docker update --restart=always 容器Id 或者 容器名
或
docker container update --restart=always 容器Id 或者 容器名
docker login
#导出镜像的命令 save 保存 /data/nginx.image下起个名 镜像
docker save -o /data/nginx.image/nginx-1.21.5.tar nginx:1.21.5
#导入镜像 docker image load 从本地文件.tar加载镜像
docker image load -i /opt/centos.tar
docker image load < /opt/centos.tar
#容器的导出
格式:docker export 容器id/名称 > 文件名 #导出
eg: docker export 21f > centos-exp
#容器的导入
docker import
#将文件拷贝到容器内(无论容器是否开启都可以拷贝)
//将本地的镜像上传到镜像仓库,要先登陆到镜像仓库
docker push 选项 本地镜像
#eg:docker push tomcat:8.0.52
//将宿主机下的/root/anaconda-ks.cfg拷贝到容器内的/tmp下 相反在容器里边也可以将文件拷贝到宿主机内
docker cp 宿主机文件路径 容器id:/路径
eg:docker cp /root/anaconda-ks.cfg 1708ad171a07:/tmp
//删除容器运行过的记录
docker rm 镜像id
//删除镜像(被删除的镜像不得有依赖的容器记录)但加-f参数可以强制删除
docker rmi 镜像id(完整的或者前三位也可以)/镜像名
docker rm -f 容器id
//删除全部镜像
docker rmi `docker images -aq`
//批量删除容器
docker rm `docker ps -aq`
// -it开启一个交互式的终端 --rm容器退出时删除该容器
docker run -it --rm centos bash
仓库可分为公共仓库和私有仓库
公共仓库就是所谓的网上的 大家都可以使用的
私有仓库值得就是自己本地或者公司内部使用的
官方仓库:https://hub.docker.com/
国内仓库:http://dl.dockerpool.com
仓库注册服务器才是存放仓库具体的服务器(Registry),每个服务器上都可以放置多个仓库,而每个仓库下可以放置多个镜像。每个镜像可以运行多个容器,每个容器上可以跑一个应用或应用组。
docker容器技术层通过cgroup:control group控制组,实现容器对物理资源使用的限制,限制的资源包括CPU、内存、磁盘三个方面。基本覆盖了常见的资源配额和使用量控制。
Cgroup是 linux内核提供的一种可以限制、记录、隔离进程组所使用的物理资源的机制,被 LXC及Docker 等很多项目用于实现进程的资源控制。
Cgroup是提供将进程进行分组化管理的功能和接口的基础结构,Docker中I/O 或内存的分配控制等具体的资源管理功能都是通过 Coroup.功能来实现的。这些具体的资源管理功能称为 Cgroup子系统,以下是对几大子系统的介绍。
(黑体用的较多,别的作为了解即可)
blkio: 限制块设备的输入输出控制。如:磁盘、光盘、USB 等。
cpu:限制 CPU资源的访问
cpuacct:产生Cgroup 任务的CPU 资源报告。
cpuset:限制分配单独的cpu 和内存资源。
devices:允许或拒绝对设备的访问。
freezer:暂停和恢复Cgroup 任务。
memory: 设置每个Cgroup 的内存限制以及产生内存资源报告。
net cls:用于标记每个网络包。
ns: 命名空间子系统。
perf_event:增加了对每 group 的监测跟踪的能力,可以监测属于某个特定的group 的所有线程以及运行在特定cpu上的线程
–cpuset-cpus、–cpuset-mems参数只在多核、多内存节点上的服务器上有效,并且必须又实际的物理配置匹配,否则也无法达到资源控制的目的。
与操作系统类似,容器可使用的内存包括俩部分:物理内存和swap。docker通过下面俩组参数来控制容器内存咋使用量
如:docker run -it -m 200M --memory-swap=300M progrium/stress --vm1 --vm-bytes 280M
–vm1:启动一个内存工作线程。
–vm-bytes 280M:每个线程分配280M内存
如果让工作线程分配的内存超过300M,分配的内存超过限额。stress线程报错。容器就会退出
在docker中若要想实现容器数据的持久化,(所谓的持久化即数据不随着container的结束而销毁),需要将数据从宿主机挂载到容器中,目前docker提供了三种不同的方式将数据从宿主机挂载到容器中。
//方二:volume创建卷
[root@localhost ~]# docker volume create nginx-data #创建一个卷
[root@localhost ~]# docker volume ls #查看卷
[root@localhost ~]# docker run -itd --name=nginx -p 8000:80 -v nginx-data:/usr/share/nginx/html nginx
4a8ba499ab24646c19896aa6862cf0081e2dcbb61f19460650f65c4d2397d71b
[root@localhost ~]# docker volume inspect nginx-data #查看创建卷的具体信息
[
{
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginx-data/_data",
"Name": "nginx-data",
"Options": {},
"Scope": "local"
}
]
[root@localhost ~]# docker exec -it 4a /bin/bash
root@4a8ba499ab24:/# ls -l /usr/share/nginx/html/
total 8
-rw-r--r-- 1 root root 497 Dec 28 2021 50x.html
-rw-r--r-- 1 root root 615 Dec 28 2021 index.html
//退出,在宿主机下查看
[root@localhost ~]# ls /var/lib/docker/volumes/nginx-data/_data
50x.html index.html
#浏览器访问 ip:端口号
//可以看到容器里面的俩个默认页面,由此可知volume帮助我们做了类似于一个软链接的功能。在容器内的改动,我们可以在宿主机里感知,而在宿主机里面的改动,容器里边可以感知到
//更改默认页面
[root@localhost ~]# echo 'yys' > /var/lib/docker/volumes/nginx-data/_data/index.html
#再次使用浏览器访问 ip:端口号
//如果我们手动stop并且remove当前nginx容器,我们会发现容器卷里面的文件还在,并且没有随着容器被删除掉
docker stop 4a
docker rm -f 4a
[root@localhost ~]# ls /var/lib/docker/volumes/nginx-data/_data/
50x.html index.html
#从而验证数据卷里边的东西是可以持久化的,如果下次还需要创建一个nginx容器,那么直接使用当前数据卷里边的文件就可以
[root@localhost ~]# docker run -d --name nginx-2 -p 9000:80 -v nginx-data:/usr/share/nginx/html nginx
#在使用原来的数据卷启动一个nginx 使用浏览器访问测试 ip:端口号
//清理卷 如果不使用自定义数据倦了,那么可以手动清理掉
docker volume ls #查看数据卷
docker volume rm 卷名称 #删除数据卷(先将容器停掉在删除对应卷)
//注意:
1.数据卷下无文件,显示容器对应目录下的文件
2.数据卷下有文件,显示数据卷原有文件,并将容器对应目录的文件影藏,显示数据卷文件
//方一:
#注:-v 指定宿主机目录持久化运行在centos里边,创建一个文件然后退出,目前所有的container的数据都存在/var/lib/docker/volumes下边加容器完整id(可以tab出来)的_data下就可以看到创的文件
[root@localhost ~]# docker run -it -v /opt/ centos /bin/bash
[root@5e475d3f5548 /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
[root@5e475d3f5548 /]# touch /opt/yys
[root@5e475d3f5548 /]# ls -l /opt/
-rw-r--r-- 1 root root 0 Mar 7 06:16 yys
[root@5e475d3f5548 /]# exit
[root@localhost ~]# ls /var/lib/docker/volumes/
d0c8d6e25af4615347cd10c5d55f9b2bb6e2c15b48b9d24c4e291babdb50840c
metadata.db
[root@localhost ~]# ls /var/lib/docker/volumes/d0c8d6e25af4615347cd10c5d55f9b2bb6e2c15b48b9d24c4e291babdb50840c/_data/
yys
//以nginx举例:
#注:创建一个目录并进去, ${PWD}是显示当前路径,映射到容器内nginx的默认页面下/usr/share/nginx/html
[root@localhost ~]# mkdir -p /data/project
[root@localhost ~]# cd /data/project/
[root@localhost project]# mkdir data
[root@localhost project]# pwd
/data/project
[root@localhost project]# ls
data
[root@localhost project]# docker run -d --name nginx-demo -p 8000:80 -v ${PWD}/data:/usr/share/nginx/html nginx
[root@localhost project]# docker exec -it 41b /bin/bash
root@41b40813a2b2:/# ls -l /usr/share/nginx/html/
total 0
#但是这样宿主机的data下边是没有任何东西的,但是我们可以先运行nginx,将nginx的默认页面拷贝到当前目录下,/data目录就没用了,在启动nginx时候指定cp下来的html目录即可,进入到起来的容器内查看会有俩个文件,为了验证可以修改nginx的默认页面,退出容器查看宿主机拷贝内的默认页面也发生改变,这就是持久化.
[root@localhost project]# docker run -d --name nginx-demo -p 8000:80 nginx
af2b94e070602549bc561567aa372d7805757f0d51931e70b1e494950fccee32
[root@localhost project]# docker cp nginx-demo:/usr/share/nginx/html/ ./
[root@localhost project]# ls
html
[root@localhost project]# ls html/
50x.html index.html
[root@localhost project]# docker run -d --name nginx-ceshi -p 8080:80 -v ${PWD}/html:/usr/share/nginx/html nginx
[root@localhost project]# docker exec -it nginx-ceshi /bin/bash
root@3a67130e2fd9:/# ls /usr/share/nginx/html/
50x.html index.html
root@3a67130e2fd9:/# echo 'this is yys' > /usr/share/nginx/html/index.html
root@3a67130e2fd9:/# exit
exit
[root@localhost project]# ls
html
[root@localhost project]# cat html/index.html
this is yys
在docker中容器默认无法与外部通信的,需要在启动命令中加入对应的选项才允许容器与外界通信
容器互联是除了端口映射外另一种可以与容器的通信方式。端口映射的用途是宿主机网络与容器的通信,而容器互联是容器之间通信
当前实现容器互联有俩种方式,一种是把俩个容器放进一个用户自定义的网络中,另一种是使用–link参数(即将删除的功能)
//它会在源和接收容器之间创建一个隧道,接受容器可以看到源容器指定的信息
--link参数格式:--link name:alias 其中name是要链接的容器名称,alias是这个链接的别名,如果启动的容器没有名称使用docker rename重命名容器
eg:docker run -itd --name=link test:text busybox
一个容器可以同时加入多个网络,使用不同地址可以访问不同网络中的容器
//拉取busybox镜像用作实验,此镜像自带一些工具
1.首先创建俩个容器
docker run -itd --name container1 busybox
docker run -itd --name container2 busybox
2.查看默认网络模式有几种
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
a784dd59a335 bridge bridge local
5a186d09d686 host host local
e56f2344ceec none null local
//Host模式,使用--net=host指定。
Container模式,使用--net=container:NAME_or_ID指定。
None模式,使用--net=none指定。
Bridge模式,使用--net=bridge指定,默认设置。
3.创建一个独立的容器网络使用bridge驱动(桥接模式),还有overlay和macvlan俩种模式 --subnet和--gateway可以指定子网和网关
#创建名为demo_net 类型为桥接 子网为192.168.0.0/16
docker network create -d bridge --subnet 192.168.0.0/16 demo_net
#删除创建的网络
docker network rm 网络name名称
#我们把container2加入到demon_net中
docker network connect demo_net container2
#查看有没有加进网络中,注意ip地址是自动分配的
docker network inspect demo_net
4.启动第三个容器
docker run --network=demo_net --ip=192.168.3.3 -itd --name=container3 busybox
--network:指定容器要加入哪个创建的网络
--ip:指定容器IP
--name:容器名称
busybox:使用什么镜像启动
5.分别查看三个容器内的网卡,进行对比
docker exec -it container1 ifconfig
docker exec -it container2 ifconfig
docker exec -it container3 ifconfig
#测试ping一下
docker exec -it container2 ping -c 3 192.168.0.2
docker exec -it container2 ping -c 3 192.168.3.3
工作模式:如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的network namespace,而是和宿主机共用一个root network namespace,容器不会虚拟出自己的网卡,配置自己的ip等,而是使用宿主机的ip和端口。生产环境注意安全
//使用busybox镜像启动容器网络模式为host
host模式特点:与宿主机使用相同的端口
docker run -itd --net=host --name=host busybox
验证:宿主机ifconfig查看本机ip
docker exec -it host ifconfig #俩网卡是否一致
这个模式可以指定新建的容器和已经存在的一个容器共享一个network namespace,而不是和宿主机共享,新建的容器不会创建自己的网卡,配置自己的ip,而是和一个指定的容器共享一个ip、端口范围等。
使用–net=container:container_name指定
//启动一个容器
docker run -itd --name host1 busybox
//在起一个容器关联上之前那个
docker run -itd --net=container:host1 --name=host2 busybox
--net:指定网络模式
container:host1 #要关联的容器名称
//验证网卡是否一致
docker exec -it host1 ifconfig
docker exec -it host2 ifconfig
在这种模式下,docker容器用有自己的network namespace,但是并不为docker容器进行任何网络配置,也就是说,这个docke容器没有网卡、IP、路由等信息。需要我们自己为docker容器添加网卡、配置ip等
使用–net=none指定,不会配置任何网络,(基本不会使用)
//使用busybox镜像启动一个名称为none的容器网络模式为none
docker run -itd --name=none --net=none busybox
//查看 docker exec -it none ifconfig
bridge模式是Docker默认的网络设置,属于一种NAT网络模式
Docker daemon在启动的时候就会建立一个docker0网桥(通过-b参数可以指定),每个容器使用bridge模式启动时,Docker都会为容器创建一对虚拟网络接口(veth pair)设备,这对接口一端在容器的Network Namespace,另一端在docker0,这样就实现了容器与宿主机之间的通信。 iptables -nvl -t nat
docker网络映射机制都是基于iptables实现
**区别:**四层代理只进行一次tcp请求,而七层代理进行了俩次tcp请求
七层负载均衡的cpu密集程度比基于包的四层负载均衡更高,他运用缓存的方式来卸载上游服务器较慢的连接,并显著地提高了性能。
当我们使用docker pull 拉取一个镜像的时候发现是下载了多行信息,最终又得到了一个完整的镜像文件,一个完整的docker镜像可以创建处docker容器的运行,例如一个centos:7.8.2003镜像文件,我们获取的是centos7这个发行版,这个镜像文件是不包含linux内核的
ls /var/lib/docker/image/overlay2/imagedb/content/sha256/
该文件作用是记录镜像和容器的配置关系
https://hub.docker. com/_/centos?tab=tags&page=1&ordering-last_updated
所有对容器的修改动作,都只会发生在容器里,只有容器层是可写的其余镜像层都是只读的
文件操作 | 说明 |
---|---|
添加文件 | 在容器中创建文件时,新文件被添加到容器中 |
读取文件 | 在容器中读取某个文件时,docker会从上往下依次在各镜像层中查到文件,一旦找到,立即将其复制到容器层。然后打开并读入内存 |
修改文件 | 在容器中修改已存在的文件时,docker会从上往下依次在各镜像层中查找到文件,一旦找到,立即将其复制到容器层,然后修改 |
删除文件 | 在容器中删除文件时,docker也是从上往下依次在镜像层中查找此文件,找到后,会在容器中记录下此操作。(只是记录删除操作) |
只有当需要修改时复制一份数据。这种特性被称作copy-on-write,可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何操作
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有的镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享
例开发机器想装东西但是又不想搞乱当前机器的环境,该怎么办?
1.下载安装docker工具
2.获取软件的docker镜像(以后想要的各种工具,基本上都能够搜索到合适的镜像去用)下载nginx镜像: docker pull nginx
3.运行nginx镜像,然后就启动了一个容器,这个nginx服务就运行在容器中
4.停止容器,删除该镜像,你的电脑上就好像没有使用过nginx一样,就好比沙箱一样的环境
沙箱:沙箱是一个虚拟系统程序,沙箱提供的环境相对于每一个运行的程序都是独立的,而且不会对现有的系统产生影响
**作用:**用于构建docker镜像,部署一个用于运行你所需的容器环境,相当于一个脚本,通过dockerfile自己的指令,来构建软件依赖,文件内依赖,存储,等等…
定制docker镜像方式
手动修改内容,然后docker commit提交容器为新的镜像
基于dockerfile中定义一系列的命令和参数构成的脚本,然后这些命令应用于基础镜像,依次添加层,最终生产一个新的镜像,极大的简化了部署工作
官方dockerfile实例:https://github.com/CentOS/CentOS-Dockerfiles
dockerfile主要组成部分:
基础镜像信息 FROM centos:tag(版本)
制作镜像操作指令RUM yum -y install openssh-server
容器启动时执行指令CMD [“/bin/bash”] 要做的事
RUN yum -y install vim
特性和COPY基本一致,不过多了一些功能:
都是拷贝宿主机的文件到容器内,仅拷贝。但是能够保留源文件的元数据,如:权限、访问时间等等
copy指令从宿主机复制文件--目录到新的一层镜像内
eg: copy yys.py /home
#支持多个文件,以及通配符形式复制,语法要满足Golang的filepath.Match
eg: copy yys* /tmp
用于在dockerfile中,目录的切换,更改工作目录
WORKDIR /opt
容器在运行时,应该在保证在存储层不写入任何数据,运行在容器内产生的数据,推荐是挂载,写入到宿主机内,进行维护
#将容器的/data文件夹,在容器运行时自动挂载为匿名卷,任何向该目录中写入数据的操作,都不会被容器记录,保证的容器存储层无状态理念
VOLUME /data
方式:
1)容器数据挂载的方式,通过dockerfile,指定VOLUME目录
2)通过docker run -v 参数,直接设置需要映射挂载的目录
帮助使用该镜像的人,快速理解该容器的一个端口业务
docker port 容器id ##查看容器端口
docker run -p ##宿主机端口:容器端口
docker run -P ##随机宿主机端口:容器内端口
用法,注意是双引号
CMD [“参数1”,"参数2”]
在指定了entrypoint指令后,用CMD指定具体的参数
docker不是虚拟机,容器就是一个进程,既然是进程,那么程序在启动的时候需要指定些运行参数,这就是CMD指令作用
例如centos镜像默认的CMD是/bin/bash,直接docker run -it centos会直接进入bash解释器也可以启动容器时候,指定参数,docker run -it centos cat /etc/os-releasea
CMD运行she11命令,也会被转化为she11形式
eg:CMD echo SPATH13
会被转化为
CMD ["sh","-c","echo $PATH"]
$容器内运行程序
这里要注意的是,docker不是虚拟机的概念,虚拟机里的程序运行,基本上都是在后台运行,利用systemctl运行,但是容器内没有后台进程的概念,必须在前台运行。
容器就是为了主机进程而存在的,主进程如果退出了,容器也就失去意义,自动退出。例如:
CMD systemctl start nginx #这样的写法是错误的,容器会立即退出
因为systemctl start nginx 是希望以守护进程形式启动nginx,且CMD命令会转化为
CMD [ "sh","-c","ehco $PATH"]
这样的命令主进程是sh解释器,执行完毕后立即结束了。因此容器也就推出了
因此正确的做法应该是CMD ["nginx","-g","daemon off;"]
ARG和ENV一样,设置环境变量,区别在于ENV无论实在镜像构建时,还是容器运行时,该变量可以使用。ARG只是用于构建镜像需要设置的变量,容器运行时就消失了
ENV JAVAPATH /usr/local # 指定JAVAPATH变量的值为/usr/local/
ENV PATH $JAVAPATH/bin # 利用 $ 引用上面的JAVAPATH
和RUN指令-样,分为两种格:
exec
shell
作用和CMD-样,都是在指定容器启动程序以及参数。
当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,而是把CMD的内容当作参数传递给ENTRYPOINT指令。
CMD和ENTRYPOINT的区别:
一个dockerfile中可以写多个CMD指令但是只有最后一个执行
ENTRYPOINT不会被运行的command命令覆盖
USER root
USER tom
…
要求:通过dockerfile,构建nginx镜像,且运行容器后,生成的页面是自己编辑的东西: 创建Dockerfile,文件名必须是这个
//创建一个目录将tar包、Dockerfile、nginx_install.sh放一起
1.创建文件夹
mkdir nginx_dockerfile
cd nginx_dockerfile
2.编写dockerfile,注意Dockerfile首字母大写
# vim nginx_dockerfile/Dockerfile
FROM centos:7
ADD nginx-1.16.1.tar.gz /usr/local
COPY nginx_install.sh /usr/local
RUN sh /usr/local/nginx_install.sh
EXPOSE 80
3.编写脚本
# vim nginx_install.sh
#!/bin/bash
yum -y install gcc gcc-c++ make pcre pcre-devel zlib zlib-devel
cd /usr/local/nginx-1.16.1
./configure --prefix=/usr/local/nginx && make && make install
[root@bogon nginx_dockerfile]# pwd
/root/nginx_dockerfile
[root@bogon nginx_dockerfile]# ls
Dockerfile nginx-1.16.1.tar.gz nginx_install.sh
#构建dockerfile 去/nginx_dockerfile目录下有Dockerfile文档
docker build -t mycentos:nginx .
//参数选项:
-f Dockerfile的名称
-t 打标签(起名)
#运行nginx镜像
docker run -itd -p 80:80 --name nginx_1 nginx
//验证:浏览器查找宿主机ip 是否能访问到自己编写的默认页面
##这就是dockerfile即dockerfile指令带来的便捷
Docker Compose的前生是Fig,它是一个定义及运行多个Docker容器的工具,可以使用YAML文件配置应用程序的服务,然后使用单个命令,可以创建并自动配置中的有服务,docker compose会通过解析容器间的依赖关系,(linx、网络容器、net-from或数据容器、)按先后顺序启动所定义的容器
Compose是Docker的服务编排工具,注意用来构建基于Docker的复杂应用,Compose通过一个配置文件来管理多个Docker容器,非常适合组合使用多个容器进行开发的场景
docker-compose 是用来做 docker 的多容器控制,有了 docker-compose 你可以把所有繁复的 docker 操
作全都用一条命令自动化完成。从上图可以看到,这位compose 非常开心的把N多个容器抓在一起,根据自己的心情来编排部署。
Docker对于运维或开发者来说,Docker 最大的优点在于它提供了一种全新的发布机制。这种发布机制,指的是我们使用 Docker 像作为统一的软件制品载体,使用 Docker 容器提供独立的软件运行上下文环境,使用 Docker Hub 提供像统一协作,最重要的是该机制使用Dockerfile 定义容器内部行为和容器关键属性来支撑软件运行。
Dockerfle作为整个机制的核心。在 Dockerfile中不但能够定义使用者在容器中需要进行的操作,而且能够定义容器中运行软件需要的配置,于是软件开发和运维终于能够在一个配置文件上达成统一。运维人员使用同一个 Dockerfile能在不同的场合下“重现”与开发环境
先来了解一下我们平时是怎么样使用 docker的!把它进行拆分一下:
上面“docker run-itd 像名称“这只是最小的动作,如果你要映射硬盘,设置nat 网络或者映射端口等等。就要做更多的 docker 操作,这显然是非常没有效率的,况且如果你要大规模部署,是不是觉得就很麻烦了。
但是我们写在 docker-compose 里面就很好了。你只需要写好后只运行一句:docker-compose up -d
编排,即orchestration,它根据被部署的对象之间的耦合关系,以及被部署对象环境的依赖,制定部署流程中各个动作的执行顺序,部署过程所需要的依赖文件的存储位置和获取方式,以及如何验证部署成功。这些信息都会在编排工具中以指定的格式(比如配置文件或者特定的代码)来要求运维人员定义并保存起来,从而保证这个流程能够随时在全新的环境中可靠有序地重现出来。
部署,即deployment,它是指按照编排所指定的内容和流程,在目标机器上执行编排指定环境初始化,存放指定的依赖和文件,运行指定的部署动作,最终按照编排中的规则来确认联署成功
这么来解释吧,编排是一个指挥家,他的大脑里存储了整个乐曲的演奏流程,对于每一个小节每一段音乐的演奏方式、开始、结束他都了然于胸;部署就是整个乐队,他们严格按照指挥家的意图用乐器来完成乐谱的执行,在需要时开始演奏,又在适当的时机停止演奏。最终,两者通过协作就能把每一位演奏者独立的演奏通过组合、重叠、街接来形成高品位的交响乐。
首先,用户执行的 docker-compose up -d 指令调用了命令行中的启动方法。功能很简单明了,一个 docke-compose xml 定义了一个 docker-compose 的 project,docker-compose 操作提供的命令行参数则作为这个 project 的启动参数交由 project 模块去处理。
其次,如果当前宿主机已经存在与该应用对应的容器,docker-compose 将进行行为逻辑判断。如果用户指定可以重新启动已有服务,docker-compose 就会执行 service 模块的容器重启方法,否则就将直接启动已有容器。这两种操作的区别在于前者会停止旧的容器,创建启动新的容器,并把旧容器移除掉。在这个过程中创建容器的各项定义参数都是从docker-compose up 指令和 docker-compose xml中传入的。
接下来,启动容器的方法也很简洁,这个方法中完成了一个 Docker 容器启动所需的主要参数的封装,并在container 模块执行启动。该方法所支持的参数我想大多数朋友过是有所了解的。
最后,container 模块会调用 docker-py客户端执行向 Docker daemon 发起创建容器的POST 请求,再往后就是Docker 处理的范了,相信看过我这篇文章 Docker: 架构拆解请的朋友就明白了。
[root@localhost ~]# yum -y install docker-compose
docker-gompase [-f …] [options] [COMMAND] [ARGS…]
docker-compose 常用选项:
build 构建或重建服务
kill 杀掉容器
logs 显示容器的输出内容
ps 显示容器
pull 拉取镜像
restart 重启服务
rm 删除停止的容器
run 运行一个一次性的容器
scale 设置服务的容器数目
exec 切换到容器内
start 开启服务
stop 停止服务
up 创建并启动容器
其实这些常用命令用 docker 的命令功能是一样的。
YAML 是-种标记语言,可读性很强。类似于 XML 数据述语言,语法比 XML 简单的多。YAML 数据结构通过缩进来表示,连续的项目通过减号来表示,键值对用冒号分割,数组用括号括起来,hash 用花括号括起来。
YAML 文件格式注意事项:
在缩排中空白字符的数目并不是非常重要,只要相同阶层的元素左侧对齐就可以了(不过不能使用 TAB 字符);
docker-compse是面向单宿主机部署的,这是一种部署能力的欠缺。在更多的场合下,管理员需要面对大量物理服务器(或者虚拟机),这时如果要实现基于 docker-compose的容器自动化编排与部署,管理员就得借助成熟的自动化运维工具 (ansible、puppetchefsaltstack)来负责管理多个目标主机,将docker-compose 所需的所有资源(配置文件、用户代码)交给目标主机,然后在目标主机上执行docker-compose 指令。
同样网络和存储也比较棘手,Docker不能提供跨宿主机的网络,完全面向Dockerdaemon的 dockercompose 当然也不支持。这意味着管理员必须部署一套类似于 open vSwich的独立网络工具,而且管理员还需要完成集成工作。当好不容易把容器编排都安排妥当之后,又会发现容器还处在内网环境中,于是负载均衡、服务发现等一堆问题就面临而来了,这些问题很快能消耗掉工程师所有的耐心。
Docker Harbor有可视化的Web管理界面可以方便管理Docker镜像操作也方便简单,又提供了多个项目的镜像权限管理控制功能等。
Harbor是VMware公司开源的企业级Docker Registry项目,其目标是帮助用户迅速搭建一个企业级的Docker Registry仓库服务。它以Docker公司开源的Registry为基础,提供了管理UI。基于角色的访问控制(Role Based AccessControl)、AD/LDAP集成、以及审计日志 (Auditlogging) 等企业用户需求的功能。通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源Docker Distribution。作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全,以提升用户使用 Registry 构建和运行环境传输镜像的效率。
角色 | 操作系统 | 主机名 | IP地址 | 软件 |
---|---|---|---|---|
仓库服务 | Cenots7.8-1 | barbor01 | 192.168.200.101 | docker-ce&docker-compose&harbor-offline |
仓库服务 | Centos7.8-2 | barbor02 | 192.168.200.102 | docker-ce&docker-compose&harbor-offline |
Docker客户端 | Centos7.8-3 | client | 192.168.200.103 | docker-ce |
安装docker
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum -y install yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce
systemctl start docker
systemctl enable docker
部署compose服务:
下载compos拖进xshell添加x权限,移动到可执行目录下 echo $PATH
部署harbor服务:
Harbor被部署为多个Docker容器,因此可以部署在任何支持Docker的linux发行版上,目标主机需要安装Python、Docker和Docker Compose。
下载Harbor安装程序(俩台harbor主机)docker版本太低安装不了
1.解压
[root@harbor01 ~]# tar -xvf harbor-offline-installer-v1.5.0.tgz -C /usr/local/
2.修改Harbor参数文件 先改个名
mv harbor.yml.tmpl harbor.yml
vim /usr/local/harbor/harbor.yml
hostname = 192.168.200.101 #改为本主机ip
https: #如果没有http认证证书那就注释掉
//vim内批量注释和批量删除 在末行模式下
注释:ctrl+v 选中要注释的(上下键)开大写 i键 #键 关大写 esc键
取消注释:ctrl+v 然后选中要注释的(上下键) x键
3.启动并安装Harbor
cd /usr/local/harbor
bash -x install.sh
查看harbor启动镜像
docker-compose ps
4.如果一切正常,浏览器访问 本机ip
默认管理员的用户和密码是 admin/Harbor12345