Docker

292 阅读9分钟

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口;它基于Go语言,是目前最流行的 Linux 容器解决方案
Docker 将应用程序与该程序的依赖打包在一个文件里面;运行这个文件,就会生成一个虚拟容器,程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样;
有了 Docker,就不用担心各个环节的环境问题了


组成

docker由三部分组成:
Docker image
镜像是只读的;它用来创建container,一个镜像可以运行多个container;镜像是可以自己创建的,但是要注意镜像存储层数越少越好;
Docker container
容器是Docker的运行组件,启动一个镜像就是一个容器,容器是一个隔离环境,多个容器之间不会相互影响,保证容器中的程序运行在一个相对安全的环境中;
其内核是与物理机共享的;
Docker registry:
仓库,用来共享和管理Docker镜像,用户可以上传或者下载上面的镜像。

docker 与 vm 相较

优点:
与传统的vm相比,docker占用的资源较少,并且由于docker的物理机内核共享,就可以更快地启动,具有更好的性能,更少的隔离和更好的兼容性
缺点:
资源隔离docker没有vm好,因此安全性也存在问题。

vm vs docker

docker的安装

这里使用rpm包来安装docker(linux环境)
要注意安装时有依赖

yum install docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm container-selinux-2.21-1.el7.noarch.rpm policycoreutils-* libsemanage*
systemctl status docker.service 	#查看docker状态
systemctl start docker.service      #打开docker
docker version						#测试,如果输出docker的版本信息,说明安装成功了,就可以开始使用啦

docker常用命令

docker 容器的命令:

attach--连接容器				diff--查看更改/不同
help--查询帮助                          	inspect--查看容器详情
logs--查看容器指令输出   		        stats--查看容器资源使用率
update--更新   				build--创建  
kill--关闭				commit--提交   	    	
pause--删除没有在工作的容器 		cp--拷贝文件
top--查看容器进程    			create--创建 

docker 镜像的命令:

在这里插入图片描述

inspect--查看详情  			logs--查看指令输出 
pull--拉取镜像     			rm--删除镜像       
build--创建  				history--历史 	 
push--上传镜像				images--查询镜像   
load--导入本地镜像

其实在操作时 使用 container 或 image与不使用是一样的效果

docker相关操作

1. 使用镜像运行一个容器:

   docker run -d -p 8080:80 --name vm2 nginx  #这里使用-p 8080:80 做了一个端口连接

2. 使用Dockerfile来创建一个镜像

最好建立一个空的目录,在空的目录下进行创建Dockerfile,因为在使用dockerfile创建镜像时会读入这个目录下的所有东西

    mkdir /tmp/docker
    vim Dockerfile
    	#这里分了两个模块,将建立过程分在build里,这样会优化镜像,减小创建镜像的大小
    	#这个文件里使用的 nginx-1.14.0.tar.gz 与 dvd.repo 必须在Dockerfile所在的目录下,不然在使用Dockerfile时会报错,找不到这几个文件
    	FROM rhel7 as build					#指定基础镜像
    	COPY dvd.repo /etc/yum.repos.d/		#COPY 命令可以复制本地文件夹到镜像中
    	ADD nginx-1.14.0.tar.gz /mnt/		#ADD 命令支持添加本地的 tar 压缩包到容器中指定目录,压缩包会被自动解压为目录,也可以自动下载URL并拷贝到镜像
    	WORKDIR /mnt/nginx-1.14.2			#切换工作目录
    	RUN rpm --rebuilddb && yum install -y gcc pcre-devel zlib-devel make && yum clean all && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.14.0
    	FROM rhel7
    	COPY --from=build /usr/local/nginx /usr/local/nginx
    	CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
    docker build -t rhel7:nginx .				#建立镜像

3.docker 共享存储
在创建容器时使用 -v 参数可以挂载一个或多个数据卷到当前运行的容器中, -v的作用是将宿主机上的目录作为容器的数据卷挂载到容器中,使宿主机和容器之间可以共享一个目录.
这样我们就可以使用存储卷插件,将docker的数据保存在物理机上
这里使用的存储卷插件是基于nfs文件系统的;
(1)先部署nfs:

#server1上
mkdir /mnt/nfs
yum install -y nfs-utils
systemctl status nfs		#先不打开服务
systemctl status rpcbind	#这个服务要是运行状态
vim /etc/exports
    	/mnt/nfs        *(rw,no_root_squash)
systemctl start nfs
exportfs -v			#查看
#server2上
yum install -y nfs-utils
showmount -e 172.25.68.100
mkdir /mnt/nfs
mount 172.25.68.100:/mnt/nfs/ /mnt/nfs/  #挂载上即可

(2)再配置convoy插件(存储插件,支持不同的后端存储,为docker提供MountPoint,也就是一个目录)

# server1,server2同样的配置
tar zxf convoy.tar.gz 
cd convoy
cp convoy convoy-pdata_tools /usr/local/bin/
cd /usr/local/bin/
ll
   total 42468
   -rwxr-xr-x 1 root root 20416312 Feb 16 14:55 convoy
   -rwxr-xr-x 1 root root 23068627 Feb 16 14:55 convoy-pdata_tools
scp * server2:/usr/local/bin/
cd /etc/docker/
ls
   key.json
mkdir plugins
cd plugins/
convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &> /dev/null &
cd /var/run/convoy/
echo "unix:///var/run/convoy/convoy.sock" > /etc/docker/plugins/convoy.spec
#之后就可以使用了
convoy create vol1
convoy list		#同样server2上也可以查看到
  {
	  "vol1": {
		  "Name": "vol1",
		  "Driver": "vfs",
		  "MountPoint": "",
		  "CreatedTime": "Sat Feb 16 15:07:08 +0800 2019",
		  "DriverInfo": {
			  "Driver": "vfs",
			  "MountPoint": "",
			  "Path": "/mnt/nfs/vol1",
			  "PrepareForVM": "false",
			  "Size": "0",
			  "VolumeCreatedAt": "Sat Feb 16 15:07:08 +0800 2019",
			  "VolumeName": "vol1"
		  },
		  "Snapshots": {}
	  }
  }
  
docker run -it --name vm1 -v vol1:/data --volume-driver=convoy ubuntu

docker底层实现技术补充之NameSpace和Cgroups

容器实现的基础是NameSpace和Cgroups。
NameSpace实现了对容器(进程)的隔离,NameSpace技术实际上修改了应用进程看待整个计算机“视图”,也就是作用域, 即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容,实现方式类似于将全局变量修改为了局部变量。

Cgroup实现了对容器(进程)资源的限制,但是在容器内部依然缺省挂载了宿主机的procfs的/proc目录, 其包含:meminfo,cpuinfo,stat,uptime等资源信息
一些监控工具如 free/top会依赖上述文件获取资源配置和使用情况

1.CPU的控制:

cd /sys/fs/cgroup/cpu
mkdir x1
cd x1/
cat cpu.rt_period_us
1000000
cat cpu.cfs_quota_us
-1
echo 20000 > cpu.cfs_quota_us 	#限制在20%之内
cat cpu.cfs_quota_us 
20000
docker run -it --name vm1 --cpu-period 100000 --cpu-quota 20000 ubuntu

2.内存的控制:

cd /sys/fs/cgroup/memory/
mkdir x2
cd x2/
cgexec -g memory:x2 dd if=/dev/zero of=bigfile bs=1M count=30
free -m
              total        used        free      shared  buff/cache   available
Mem:            488         106          55          12         326         339
Swap:          1023          40         983
cd /sys/fs/cgroup/memory/x2/
echo 20971520 > memory.memsw.limit_in_bytes 
 cd /dev/shm
cgexec -g memory:x2 dd if=/dev/zero of=bigfile bs=1M count=30
docker run -it --name vm1 --memory 20M --memory-swap 20M ubuntu
root@ece596ac3a6b:/# free -m		#因为容器没法完全隔离所以 这里显示的信息是物理机的信息,实际上设置已经生效了
             total       used       free     shared    buffers     cached
Mem:           488        433         55          2          0        272
-/+ buffers/cache:        160        328
Swap:         1023         20       1003

注:可以使用lxcfs来进行容器与物理机的隔离 把宿主机的 /var/lib/lxcfs/proc/memoinfo 文件挂载到Docker容器的/proc/meminfo位置后。容器中进程读取相应文件内容时,LXCFS的FUSE实现会从容器对应的Cgroup中读取正确的内存限制。从而使得应用获得正确的资源约束设定。

yum install -y lxcfs-2.0.5-3.el7.centos.x86_64.rpm 
lxcfs /var/lib/lxcfs &
cd /var/lib/lxcfs/
docker run -it -m 20M -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo -v /var/lib/lxcfs/proc/diskstats:/proc/diskstats -v /var/lib/lxcfs/proc/meminfo:/proc/meminfo -v /var/lib/lxcfs/proc/stat:/proc/stat -v /var/lib/lxcfs/proc/swaps:/proc/swaps -v /var/lib/lxcfs/proc/uptime:/proc/uptime ubuntu
root@b9a67b16ad38:/# 
容器里的用户其实并没有超级权限,但是有时环境需要很大的权限,那么就可以在创建容器的时候就加上超级权限:
docker run  -it --privileged=true --name vm1 ubuntu
这样在这个vm1内,用户就可以查看磁盘信息,添加ip等之前并不能进行的操作
但是又有时超级权限给的太大了,这时可以在创建容器的时候制定白名单来指定容器内用本不能但实验需要的操作:
docker run -it --cap-add=NAT_ADMIN --name vm2 ubuntu

docker 网络

网络连接方式:
桥接网络模型 虚拟网络对 (容器run时网络默认是桥接的模式)
host网络模型 (外界主机可以直接访问,没有容器隔离)
container网络模型 (跟宿主机的网络模式有关)容器间的通信
none网络模型 ()

注: Docker在启动时会创建一个虚拟网桥docker0,默认地址为172.17.0.1/16,容器启动后都会被桥接到docker0上,并递归的分配一个IP地址;
这里docker不想要172.170.1网段的ip可以改变docker的默认网络配置: 编辑json文件:

vim /etc/docker/daemon.json 
	{"bip":"17.25.100.1/24"}
systemctl restart docker.service 
ip addr show docker0		#就会发现docker0的网段改变了

除了自带的这几种网络连接模式,还可以自定义网络模式(下面的例子是自定义的桥接网络连接模式)
一般情况下建议使用自定义网络,这样灵活性比较高
ps :只有自定义网络可以指定ip

docker网络的小实验:
其实验内容大概是:
建立两个虚拟网段;创建两个容器分别使用不同的网段;检查并测试两个容器的网络连通性
正常情况下两个容器是没有办法进行通信的,但可以使用connet命令将容器来连接上另一个容器的网段,这样就可以进行容器间的通信

docker network create --driver bridge --subnet 172.18.0.1/24 --gateway 172.18.0.1 my_net1
docker network create --driver bridge --subnet 172.19.0.1/24 --gateway 172.19.0.1 my_net2

docker network ls   #查看网络

docker run -it --name vm1 --network my_net1 ubuntu

docker run -it --name vm2 --network my_net2 --ip 172.19.0.68 ubuntu

docker attach vm1		

在容器vm1里面查看ip,ping172.18.0.1,与172.19.0.1 虽然vm1与172.19.0.1在不同的网段但是可以ping通,是因为这两个网关都是在物理机上的,是互通的,试一试ping 172.19.0.68 就会发现vm1是ping不通vm2的

docker attach vm2	#容器vm2同理
brctl show
docker network connect my_net2 vm1 #给容器vm1连接上与vm2同样的网络,这样vm1就可以ping通vm2了

csdn博客地址: blog.csdn.net/kooka_/arti…