docker基础——从入门到精通

一个完整的docker由几个部分组成?
 docker client
 docker daemon
 docker images
 docker containers
容器是一个存储、运输工具,它能对容器内部的东西做出环境隔离,也就是能虚拟出相对隔离的环境。
镜像:创建容器所使用的模板,存放在镜像仓库中。
docker是一个c/s架构
 
docker 与 kvm 的对比
kvm是虚拟出来的虚拟机,也就是整个操作系统,使用起来比较复杂,启动的过程也相对较慢,模板文件较大。
但是虚拟出来的系统和物理完全隔离,虚拟的完整的系统,可以登录并实现管理。
docker是虚拟出来一个用户空间,使用起来非常轻便简单,启动的速度非常快,模板文件很小,在一定程度上和物理机隔离
仅仅是虚拟出来一部分用户空间,不方便管理。
 
docker使用理由
快速部署、实现隔离、一个主机可以运行多个容器、提高开发的效率
简化配置过程,实现软件的跨平台。
docker拉取镜像是在dokerhub上拉去,所以要配置阿里云的容器镜像的加速服务。
docker的部署:
阿里mirros上找到docker-ce.repo的yum源,并下载。
然后执行yum install docker-ce -y
然后在docker配置阿里的镜像加速,然后启动docker的后台进程。

docker-image操作
 docker image ls
 docker pull busybox
 docker image history busybox
 docker image history busybox --no-trunc
 docker image save busybox > busybox.tar
 docker image save busybox:1.31.0 -o busybox.tar
 docker image rm busybox
 docker image rm busybox:1.31.0
 docker image load < busybox.tar
 docker image load -i busybox.tar
 docker image inspect busybox
 docker image prune
 docker image prune -f
 docker iamge tag busybox:1.31.1 ken:v1
built —— 基于dockerfile
push —— 镜像仓库
import —— 基于容器来制作image

docker 容器操作
 docker run -d nginx
 docker ps
 docker ps --no-trunc
 docker inspect container-name
 docker -v
 docker对内核的要求较高,内核版本至少3.8以上,uname -r查看内核版本。
 export导出的镜像使用import导入时,在run的时候,需要手动输入后台要一直运行的命令,如:
 docker run -d nginx sh  ,否则会闪退,因为docker是执行完所有要执行的命令就会自动退出。
 docker run -d --name nginx nginx
 docker ps   —— docker container ls
 docker stop container-name
 docker ps -qa
 docker ps -a
 docker stop $(docker ps -qa)
 docker rm $(docker ps -qa)
 docker rm cotainer-id #无法删除正在运行的容器
 docker rm -f cotainer-id #可以-f强制删除
 docker run -d --name nginx --rm nginx
 docker start container-id
 docker kill container-id
 docker pause container-id
 docker unpause container-id
 docker log nginx
 docker log nginx -f
 docker stats nginx #查看容器的cpu,mem,netio等
 docker top nginx #查看uid pid等
 docker inspect nginx
 docker wait nginx #打印退出返回码
 docker container prune -f #删除已经停掉的容器。
 docker exec nginx touch ken
 docker exec nginx ls /
 docker exec -it nginx sh
 docker exec -it nginx bash
 docker attach nginx #容器会自动退出
 docker run -it busybox #执行完命令自动就退出了。
 docker exec busybox ip a
 docker history nginx
 docker diff nginx #告诉你哪些文件被改动了
 docker cp nginx:/test.txt .
 docker cp test.txt nginx:/
 docker exec nginx ls /

docker端口映射
-p -P
实现了外部网络访问内部容器的服务
-P:容器端口映射为宿主机的一个随机端口
-p:容器端口映射为宿主机的一个特定端口、特定网卡上的随机端口、特定网卡上的特定端口。
多个端口使用多个-p来进行特定端口或者特定网卡的映射。
 docker run -P -d nginx
 docker port container-id
 docker run -d -p 80:80 nginx
 docker run -d -p 192.168.27.20::80 nginx
 docker run -d -p 192.168.27.20:81:80 nginx
 docker rm -f container-id
run使用的是相同的镜像但是启动的是完全不同的容器。

镜像的制作
commit制作镜像
dockerfile 制作镜像
tar包制作镜像
 
commit制作镜像
 为了保持数据的一致性,在使用commit制作镜像的时候,加上-p,commit制作的镜像实际上是保存了写入的内容。
 docker commit -p nginx ken:v1
 docker image ls
 直接从容器到镜像的制作方式。
 docker run -d ken:v1
 docker commit -p nginx ken:v2
 docker run -it ken:v2 cat test1
使用tar包制作镜像
 image —— image : save load
 cotainer—— image : export import #注意没有后台执行的CMD
 docker export nginx > nginx.tar
 tar -xf ngnix.tar #会发现实际上就是容器
 docker import nginx.tar ken:v3
 docker image ls
 docker run -d ken:v3 bash
 docker history ken:v3
 docker history nginx
dockerfile制作镜像
使用dockerfile制作的镜像里面的每一行就是申明镜像的每层内容。
通过docker history nginx 可以看到一层层的内容。
编写的注意事项:#——表示注释 第一个非注释行一定要是FROM指令
    编写dockerfile必须在一个目录下进行,这个目录就是dockerfile的工作目录
    Dockerfile的文件名的首字母必须是大写:Dockerfile
    制作镜像所要使用的文件必须放在工作目录之下,或者工作目录的子目录下面,不能放到其他目录之中。
    基于dockerfile制作镜像本质上还是基于现有镜像去制作镜像。
    可以通过隐藏文件.dockerignore来指定不要放到镜像中的文件,一行是一个文件。
FROM nginx:latest
LABLE author ken
ENV name=ken age=22
ENV school kkk  #这样只能声明一个变量
RUN yum install nginx -y;systemctl restart nginx \
 mkdir ken \
 touch test
RUN yum install ngnix -y && systemctl restart nginx
COPY src dest
COPY ["src","dest"]
COPY test.txt /usr/share/nginx/html/
源文件使用相对路径,目标一边使用绝对路径。可以使用统配符,但是源文件必须要在工作目录或其子目录当中。
目标路径可以不存在,会自从创建,所以要注意你的路径。
如果源文件是目录,那么会递归复制其下的内容,而源文件的目录本身并不会被复制。
如果复制了多个文件,或者使用了通配符,那么目标路径的目录必须要以/结尾。
ADD——复制文件,可以自动解压tar包文件,可以在网络上下载文件,下载的是tar包则不可以解压。
ADD https://xxxxxxx  /date/
ADD ken.tar /date/
WORKDIR /usr/share/nginx/html/   #声明工作目录
EXPOSE 80 3306  #声明暴露的端口,只是什么而已,要真正暴露需要-p -P来实现。
VOLUME /var/lib/mysql #声明数据卷的位置,如果不映射,那么会自动挂载到宿主机的一个随机目录。
ONBUILD CMD ADD https:xxxx  #其他人在使用该镜像制作新镜像的时候会触发的动作
docker search nginx #找这种offical,ok的
docker history nginx
CMD touch test
CMD ["touch","test"]
CMD ["test1","test2"]
ENTRYPOINT touch test
ENTRYPOINT ["touch","test"]
CMD ["test1","test2"]
ENTRYPOINT ["touch"]
Dockerfile的文件名的首字母必须是大写!
docker build -t nginx:v1 .
 
docker私有仓库
docker history registry
私有仓库就是公司保存公司做的镜像的地方:
docker image load < registry.tar
docker run -d -p 5000:5000 -v /registry:/var/lib/registry registry
要推送至私有仓库,需要首先tag打上标签。
 docker image tag test1:v1 192.168.64.15:5000/test1:v2
然后更改/etc/docker/daemon.json
 systemctl daemon-reload
 systemctl restart docker
 docker push 192.168.64.15:5000/test1:v2
其他客户端拉取:
 docker pull 192.168.64.15:5000/test1:v2
 docker image tag 192.168.64.15:5000/test1:v2 test1:v2
docker run -d -p 80:80 -P lamp #大小p可以联合使用
 
docker 底层技术实现
cgroup——资源限额,全称control group ,liunx系统通过设置进程使用cpu,mem和io资源的限额。 
namespace——实现资源隔离
docker run -d -m 512M nginx
docker ps
docker stats container-id
CPU MEM I/O
docker update -m 64M container-id
docker run -d -c 512 nginx
/sys/fs/cgroup
-c设置的是cpu的相对权重值,与-m设置的不同-m设置的是limit限额。
在每个容器中能够看到文件系统,网卡等资源,这些资源看上去是容器自己的,这样使得容器看起来像是一个独立的计算机。
liunx实现这种方式的技术就是namespace,namespace管理着host中全局唯一的资源,并可以让每一个容器都觉得只有自己在使用它,
也就是说namespace实现了容器之间的资源隔离。
linux使用了六种namespace:
Mount —— mount namespace 让容器看上去拥有整个文件系统。容器有自己的/,可以mount 和 umount ,当然这些只是在当前容器中
生效,不会影响到host和其他容器。
UTS UTS namespace 让容器有自己的hostname,默认情况下容器的hostaname是容器的短id,可以通过-h或者--hostname参数设置。
 docker run -it -h ken busybox sh
 查看hostname
 docker run -it --privileged busybox sh
 在容器里面更改hostname
IPC IPC namespace:让容器拥有自己的内存和信号量来实现进程间通信,而不会和其他容器和host混淆在一起。拥有自己的虚拟内存。
PID PID namespace:容器在host当中以进程的形式运行,容器内的pid 不同于host中对应的pid,容器中的1号进程也不是systemd,
     也就是说容器拥有一套独立的pid
Network network namespace:让容器拥有独立的网卡,ip,路由等资源。
User user namespace:让容器能够管理自己的用户,host不能看到容器创建的用户。
几乎所有的镜像都是通过基础的base镜像叠加制作而来。
新的镜像是从base镜像中一层层叠加生成的,每安装一个软件,就在原有的镜像上叠加一层。
docker镜像采用的是分层结构,为什么呢?
最大的好处之一就是共享资源。如:如果多个镜像是从一个基础镜像中的来的,那么docker host只需要在磁盘上保存一份base镜像,
同时内存中加载一份base镜像,就可以为所有的镜像服务了,而且镜像的每一层都可以被共享。
如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的配置文件,其他容器是否也会被修改呢?
答案是不会!修改被限制在单个的容器里。
这就是容器的copy-on-write特性。
当一个容器被启动时,一个新的可写层就被加载到了镜像的顶部。这一层通常叫做容器层,其下的叫做镜像层。
 
volumes:数据卷
实现数据的持久化,同时也实现容器与宿主机之间的文件共享。
docker run -d -p 80:80 -v /ken:/usr/share/nginx/html/ nginx  #相当于mount
docker history httpd —— 查看iamge的历史创建信息。
历史构建信息中有VOLUME,如果不指定-v映射那么默认会自己映射host的随机卷。
指定的容器路径(/usr/share/nginx/html/)如果不存在,那么默认会自动创建。
docker 自管理挂载
docker run -it -v /test busybox
容器中/test 随机映射到/var/lib/docker/volumes/下的一个随机目录,使用docker inspect container-id
docker volume ls  —— 查看volume
 
volume的操作
docker volume ls
docker volume rm volume-name
docker volume ls | grep xxxx
在删除容器的时候删除卷:
docker rm -f -v cotainer-id
正在使用的卷,默认是删除不掉的。
docker volume rm $(docker volume ls -q)
容器之间共享数据卷:
docker run -d -p 80:80 -v /ken:/usr/local/apache2/htdocs httpd
docker run -d -p 81:80 --volumes-from container-id httpd
两个端口访问是一样的。
启动mysql容器:
docker image load < mysql.tar
docker run -d -p 3306:3306 mysql
发现起不来,起来之后就推出了。
查看日志:
docker logs container-id
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123 mysql
docker run -d -p 3306:3306 -v /mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123 mysql
 
docker 网络
docker network ls   #默认三种网络,host none bridge
docekr run -it --network=none busybox  #只有本地lo地址
docker run -it --network=host busybox  #共享了host的网络,打通了容器和宿主机的network namespace 和 hostname
host网络模式下需要注意和host主机的port冲突问题。
bridge——这也是docker默认使用的网络模式。
docker run -it --network=bridge busybox  相当于   docker run -it busybox
默认使用相同网络模式的容器的ip 在同一个网段:
docker network inspect bridge
会发现宿主机的docker0网卡是容器docker桥接模式的gateway
host bridge——能通外网,none——不能通外网
自定义网络模式:
docker network create -d bridge ken
docker run -it --network=ken busybox
同样能通外网,为什么?
docker network inspect ken
docker network create -d bridge --subnet 10.0.0.0/24 --gateway=10.0.0.1 ken1
docker run -it --network=ken1 busybox
docker run -it --network=ken1 --ip=10.0.0.5 busybox
获取特定的ip需要自定义网络才能实现。
自定义网段,自定义ip均可以通外网。

单台主机之间的容器通信:
1、通过ip地址,相同网段。
2、通过DNS
3、通过join通信
docker network connect ken container-id
相当于添加一块网卡,加入到ken网络。
docker network disconnect ken container-id
相当于卸载一张网卡。
通过DNS通信:
使用这种方法需要给容器指定容器名。
docker run -it --name a1 --network=ken1 busybox
docker run -it --name a2 --network=ken1 busybox
然后在a2之中ping a1 能够通信。DNS之间的相互通信实际上是通过容器名,而不是常见的主机名。
但是docker 的自带网络是无法通过DNS通信的,如果你自定义的网络也不能通过DNS进行通信的话,这也是正常的,有些硬件的却不支持。
通过join通信:
一个容器使用另外一个容器的network namespace
docker run -it --name:b2 busybox
docker run -it --network=container:b2 busybox
两个容器使用的是同一个network namespace
joined通信非常适合以下场景:
1、不同容器程序希望通过loopback高效快速通信。如web server 和app server
2、希望监控其他容器的网络流量,如运行在独立容器里的网络监控程序。
 
容器通外网分析
总体来讲是使用了NAT技术,进行了网络地址转换。
首先在host上查看网桥信息:
brctl show
发现docker0网卡上有一个vethbxxxxx
这个vethbxxxx在宿主机的网上能够看到,通过ip a,发现有一个vethbxxxxx@ifxx
进入容器查看ip : eth0@ifxx
实际上就是一个docker0网卡上桥接了一个veth,这个veth连接了docker容器中的eth0,两者就形成了一对veth pair
也就是说容器已经连接到了docker0这张网卡上了,那么docker0是怎么访问外网的呢?实际上就是通过iptables进行转发。
iptables -t nat -S
其中有一条规则会将来自容器的流量,只要通过docker0就会对其进行伪装,将其转换为自己的网卡。
ip r ——可以看到自己宿主机的网卡通过哪个网关去访问外网。
可以通过流量抓包来验证:
yum install tcpdump -y
tcpdump -i ens33 -n icmp
在容器里面ping外网,然后通过抓通过宿主机网卡的流量来验证。
tcpdump -i docker0 -n icmp  —— 发现是来自容器的ip访问外网,到这里会被伪装。
tcpdump -i ens33 -n icmp   ——  发现变成了自己的ens33的ip去访问外网。
整个过程:容器的eth0——>docker0——>NAT——>ens33——>外网
实际上容器的端口映射-p也是通过iptables实现的,做了一个DNAT。
 
容器监控
容器自带的三个监控命令:ps top stats logs
weave scope监控容器
weave scope的最大特点就是能够生成一张docker容器地图,能够让人直观地理解、监控和控制容器,也是个人比较喜欢的监控软件。
安装weave scope:
curl -L git.io/scope -o /usr/local/bin/scope
chmod a+x /usr/local/bin/scope
scope launch
weave scope 监听在4040端口
浏览器访问即可实现监控。
如果有多台主机需要监控:
在要监控的主机上每台均执行:scope launch ip1 ip2 ....
#前提是要在每台主机上执行:
#curl -L git.io/scope -o /usr/local/bin/scope
#chmod a+x /usr/local/bin/scope
#并且要删掉之前的运行的weave scope容器
那么就会监控你的多台主机上的容器情况了。

猜你喜欢

转载自www.cnblogs.com/getbird/p/11650467.html