docker容器就是一个虚拟机。(不准确!!!)
每个虚拟化应用程序不仅包括应用程序(可能只有数十MB)以及必要的二进制文件和库,还包括整个客户机操作系统(可能重数十GB)。
Docker容器仅包含应用程序及其依赖项。它在主机操作系统上的用户空间中作为隔离进程运行,与其他容器共享内核。因此,它具有虚拟机的资源隔离和分配优势,而且具有更高的可移植性和效率。
[](()docker的优势
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。
1.更高效的利用系统资源
docker对系统资源的利用率更高,无论是应用执行速度,内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机往往可以运行更多数量的应用。
2.更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟,而docker容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级,甚至毫秒级的启动时间,大大的节约了开发测试,部署的时间。
3.一致的运行环境
开发过程中常见的一个问题是环境一致问题,由于开发环境,测试环境,生产环境不一致,导致有些bug并未在开发过程中发现。而docker的镜像提供了除内核外完整的运行时环境(库、依赖),确保环境一致性,从而不会在出现“这段代码在我机器上没问题”这类问题。
4.持续支付和部署
docker不像传统的软件交付方式那样,只把代码以及说明文档之类的给你就完了,而是直接给你一个docker镜像作为标准的交付件,这个标准件不仅包括了应用代码本身,还包括了代码运行需要的OS等整体依赖环境。
对开发和运维人员来说,最希望就是一次创建和部署,可以在任意的地方运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付。开发人员可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合持续部署(Continuous Delivery/Deployment) 系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
5.更轻松的迁移
由于docker确保了执行环境的一致性,使得应用的迁移更加的容易。docker可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云、甚至是笔记本、其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
6.更轻松的维护和拓展
docker使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得十分简单。此外,docker团队同各个开源项目团队一起维护了一大批高质量的官网镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
对比传统虚拟机总结
| 特性 | 容器 | 虚拟机 |
| — | — | — |
| 启动 | 秒级 | 分钟级 |
| 硬盘使用 | 一般为 MB | 一般为 GB |
| 性能 | 接近原生 | 弱于 |
| 系统支持量 | 单机支持上千个容器 | 一般几十个 |
[](()感受一下docker的便利性
[Docker安装文档](()
[k8s文档中关于docker安装](()
案例1:为了保证宿主机的纯净,启动一个linux环境:
docker run -it -d centos
案例2:部署nginx
docker run -d -p 80:80 nginx:1.14-alpine
案例3: 部署MySQL5.7
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=‘111111’ mysql:5.7.20
部署DOClever:64.115.4.15
[](()一、docker的核心技术
Docker主要是使用了一些已有的技术实现的,主要的核心技术是Namespaces、Cgroup和UnionFS。
命名空间(Namespaces) 是Linux系统提供的一种内核级别的环境隔离方法,Docker 就是利用的这种技术来实现容器环境隔离的。Linux Namnespace提供了对UTS、IPC、mount、PID、network、User 等隔离机制。
UTS为Unix Timesharing System的简称。
UTS namespace主要是用来隔离hostname和domainname两个系统标识的。
IPC Namespace主要提供了进程间通信的隔离能力。使消息队列处于不同的名称空间中。
PID Namespace用来隔离进程。让每个容器的进程PID使用独立的名称空间。
Network Namespace是用来隔离网络。Network Namespace可以让每个容器拥有自己的网络设备、端口、IP 地址等。因为其网络是完全隔离的,所以每个Namespace下的端口不会产生任何冲突。
既然完全隔离了,容器与外部之间需要通信该怎么办?在Docker中可以通过虚拟网桥来实现。
MountNamespace用来隔离各个进程看到的挂载点视图。在不同Namespace中的进程看到的文件系统层次是不一样的,不同的Namespace 进行mount和umount 操作只会对自己的Namespace内的文件系统产生影响,对其他的Namespace没有影响。
User Namespace可以用来隔离用户的用户组ID。在不同的User Namespace下进程的UserID和Group ID是不同的。
Cgroups是Linux系统中提供的对一组进程及其子进程进行资源(CPU、 内存、存储和网络等)限制、控制和统计的能力。
Cgroup可以直接通过操作Cgroup文件系统的方式完成使用。例如,使用mount -t cgroup cgroup /cgroup
命令进行操作,此时就会在/cgroup
下生成很多默认的文件,这就创建一个Cgroup,在这个目录下每创建一个目录就表示创建了一个子Cgroup。进入子目录会发现里面会生成一些文件与上层Cgroup即/cgroup
目录内容大致相同。这就是Cgroup文件系统的树形层次结构。
创建完Cgroup之后,可以为其分配可用的资源并将不同的进程放进去。当创建完第一-个Cgroup时,系统会把所有的进程都放到主Cgroup中,可以查看Cgroup中的tasks文件来查看此Cgroup中的进程PID;同样可以通过在tasks 中添加对应的进程PID,会把该进程放入该Cgroup中。但需要注意,如果在子Cgroup中添加-一个进程,则子Cgroup的上层Cgroup中的tasks文件中也会有这个PID,因为子Cgroup属于上层Cgroup,所以子Cgroup中的进程也同时会属于上层Cgroup,但是同一层级的Cgroup却不能同时拥有同一个进程。比如A和B这2个Cgroup是同属于C的子Cgroup,那么A和B就不能同时拥有同一个进程。至于每个Cgroup中的资源配置量都是通过设置当前Cgroup的子系统来配置的。
Cgroups为不同的资源定义了各自的Cgroup子系统,来实现对资源的具体管理。Cgroup实现的子系统及其实现的功能如下。
devices:设备权限控制。
cpuset:分配指定的CPU和内存节点。
cpu: 控制CPU占用率。
cpuacct:统计CPU的使用情况。
memory: 限制内存的使用.上限。
freezer:暂停Cgroup中的进程。
net_cls: 配合traffic controller限制网络带宽。
net_prio: 可以动态控制每个网卡流量的优先级。
blkio: 限制进程的块设备I/O。
ns: 使不同Cgroups中的进程使用不同的Namespace。
可以使用mount -t cgroup cgroup /cgroup
命令创建cgroups,其中可以通过-o
参数添加子系统,如命令mount -t cgroup -o cpu、cpuset、 memory cgroup /cgroup
。这个命令表示创建了一个名为cgroup的层级,并附加了cpu、cpuset、 memory 三个子系统,并把层级挂载到/cgroup目录上。但实际执行命令时会报出already mounted错误,且执行不成功。这是因为该命令一般在Linux发行版启动时就已经执行了,对应的子系统的Cgroup已经被创建并挂载了。并且虽然cgroupfs可以挂载在任意目录中,但是标准挂载点是/sys/fs/cgroup目录并且在启动时已经挂载上了,所以一般并不需要执行该命令。由于系统的/sys/fs/cgroup目录已经挂载了各种cgroupfs,可以直接在该Cgroup上进行操作。
首先查看/sys/fs/cgroup,如下所示。
[root@localhost ~]$ ll /sys/fs/cgroup/
'总用量 0
drwxr-xr-x 4 root root 0 3月 14 2019 blkio
lrwxrwxrwx 1 root root 11 3月 14 2019 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 3月 14 2019 cpuacct -> cpu,cpuacct
drwxr-xr-x 4 root root 0 3月 14 2019 cpu,cpuacct
drwxr-xr-x 3 root root 0 3月 14 2019 cpuset
drwxr-xr-x 4 root root 0 3月 14 2019 devices
drwxr-xr-x 3 root root 0 3月 14 2019 freezer
drwxr-xr-x 3 root root 0 3月 14 2019 hugetlb
drwxr-xr-x 4 root root 0 3月 14 2019 memory
lrwxrwxrwx 1 root root 16 3月 14 2019 net_cls -> net_cls,net_prio
drwxr-xr-x 3 root root 0 3月 14 2019 net_cls,net_prio
lrwxrwxrwx 1 root root 16 3月 14 2019 net_prio -> net_cls,net_prio
drwxr-xr-x 3 root root 0 3月 14 2019 perf_event
drwxr-xr-x 3 root root 0 4月 22 09:21 pids
drwxr-xr-x 4 root root 0 3月 14 2019 systemd
可以看到/sy/fs/cgroup目录下有很多子目录,分别对应拥有对应子系统的Cgroup, 以cpuset为例,查看cpuset目录,如下所示。
[root@localhost ~]$ ls -l /sys/fs/cgroup/cpuset/
总用量 0
-rw-r–r-- 1 root root 0 3月 14 2019 cgroup.clone_children
–w–w–w- 1 root root 0 3月 14 2019 cgroup.event_control
-rw-r–r-- 1 root root 0 3月 14 2019 cgroup.procs
-r–r–r-- 1 root root 0 3月 14 2019 cgroup.sane_behavior
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.cpu_exclusive
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.cpus
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.mem_exclusive
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.mem_hardwall
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.memory_migrate
-r–r–r-- 1 root root 0 3月 14 2019 cpuset.memory_pressure
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.memory_pressure_enabled
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.memory_spread_page
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.memory_spread_slab
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.mems
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.sched_load_balance
-rw-r–r-- 1 root root 0 3月 14 2019 cpuset.sched_relax_domain_level
-rw-r–r-- 1 root root 0 3月 14 2019 notify_on_release
-rw-r–r-- 1 root root 0 3月 14 2019 release_agent
drwxr-xr-x 4 root root 0 4月 29 14:55 system.slice
-rw-r–r-- 1 root root 0 3月 14 2019 tasks
可以看到里面有很多的控制文件,其中以cpuset开头的是cpuset子系统产生的,剩下的是由Cgroup产生的。前文已经提到过,默认所有进程的PID都是在Cgroup的根目录的tasks文件中,通过mkdir创建一个childA目录,就创建了一个子Cgroup,如下所示。
[root@localhost cpuset]$ mkdir childA
接着进入childA目录对该子Cgroup进行配置,可以通过修改文件的方式进行配置,如下所示。
[root@localhost cpuset]# echo 0 > childA/cpuset.cpus
[root@localhost cpuset]# echo 0 > childA/cpuset.mems
两个命令分别表示限制Cgroup里的进程只能在0号CPU上运行,并只会从0号内存节点分配内存。接下来是给Cgroup分配进程,上文也已经提到通过修改tasks的方式把进程添加到当前Cgroup中,如下所示。
[root@localhost cpuset]# echo $$ >childA/tasks
上面的命令表示把当前进程添加到Cgroup中,其中$$变量表示当前进程的PID。这时进程的所有子进程也会被自动地添加到Cgroup中,并受到该Cgoup资源的限制。
UnionFS(联合文件系统)是把不同物理位置的目录合并到同一个目录中的文件系统服务。其早期是应用在LiveCD领域的,通过联合文件系统可以非常快速地引导系统初始化或检测磁盘等硬件资源。这是因为只需要把CD只读挂载到特定目录,然后在其上附加一层可读写的文件层,对文件的任何变动修改都会被添加到新的文件层内,这种技术被称为写时复制。
写时复制是一种可以有效节约资源的技术,它被很好地应用在Docker镜像上。其思想是如果有一个资源需要被重复利用,在没有任何修改的情况下,新旧实例会共享资源,并不需要进行复制,如果有实例需要对资源进行任何的修改,并不会直接修改资源,而是会创建一个新的资源并在其上进行修改,这样原来的资源并不会进行任何修改,而是与新创建的资源结合在外,表现为修改后的资源状态。这样做可以显著地减轻对未修改资源的复制而带来的资源消耗问题。
下面通过讲解在Docker中如何使用UnionFS更深入地理解写时复制。
一个最常见的 rootfs,或者说容器镜像,会包括如下所示的一些目录和文件,比如 /bin,/etc,/proc 等等。Docker在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量 rootfs。
在 docker 架构中,当 docker daemon 为docker容器挂载 rootfs 时,沿用了 Linux 内核启动时的做法,即将 rootfs 设为只读模式。在挂载完毕之后,利用联合挂载(union mount)技术在已有的只读 rootfs 上再挂载一个读写层。这样,可读写的层处于 docker 容器文件系统的最顶层,其下可能联合挂载了多个只读的层,只有在 docker 容器运行过程中文件系统发生变化时,才会把变化的文件内容写到可读写层,并隐藏只读层中的旧版本文件
。
目前docker在使用的文件系统包括但不限于以下这几种:aufs, device mapper, btrfs, overlayfs, vfs, zfs。aufs是ubuntu 常用的,device mapper 是 centos,btrfs 是 SUSE,overlayfs ubuntu 和 centos 都会使用,vfs 和 zfs 常用在 solaris 系统。现在最新的docker版本中默认两个系统都是使用的overlay2。
之前centos有一段时间使用了device mapper,但其性能不佳,所以很多文章不要在centos上面使用docker,现在看来,还是可以使用的。
注意:容器使用的这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失,所以当数据需要持久化时用这个命令。
参考文章:https://www.wumingx.com/k8s/docker-rootfs.html
[](()二、docker网络
这部分主要介绍Docker的网络原理,通过Linux系统模拟实现一个Docker默认网络的方法。
首先对Docker网络的实现原理进行整体简略的介绍,当Docker服务安装并启动后,在主机上输入ifconfig 命令,可以发现主机上多了一个docker0的虚拟网桥,这个网桥为Docker的网络通信提供支持。如图所示,在默认网络情况下,当启动一个Docker容器时,Docker会为容器分配一个IP地址,并通过一对vethpair将容器的eth0绑定到主机的docker0网桥中。
下面通过Linux系统模拟Docker网络模型,实现上面介绍的网络结构。
[root@centos-7 ~]# ip netns add test
[root@centos-7 ~]# ip netns list
test
此时Namespace test 创建成功了,在/var/un/netns 目录中可以看到一个test文件。这 《大厂前端面试题解析+Web核心总结学习笔记+企业项目实战源码+最新高清讲解视频》无偿开源 徽信搜索公众号【编程进阶路】 个namespace可以理解为是一个docker容器。
当启动一个容器时,Docker 会为容器创建一个Network Namespace,可以看到在/var/run/docker/netns目录下生成一个对应的文件。
先创建veth:
[root@centos-7 ~]# ip link add veth0 type veth peer name veth1
在当前Namespace中可以看到veth0和veth1:
[root@centos-7 ~]# ip link list
1: lo:
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:
link/ether 00:1c:42:60:50:ff brd ff:ff:ff:ff:ff:ff
3: virbr0:
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
4: virbr0-nic:
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
5: veth1@veth0:
link/ether 7a:51:22:e3:a6:15 brd ff:ff:ff:ff:ff:ff
6: veth0@veth1:
link/ether a6:78:43:74:23:33 brd ff:ff:ff:ff:ff:ff
将veth1加到namespace “ test”:
[root@centos-7 ~]# ip link set veth1 netns test
通过ip link list命令发现,当前Namespapce只能看到veth0,而veth1已经找不到了。
[root@centos-7 ~]# ip link list
1: lo:
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:
link/ether 00:1c:42:60:50:ff brd ff:ff:ff:ff:ff:ff
3: virbr0:
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
4: virbr0-nic:
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
6: veth0@if5:
link/ether a6:78:43:74:23:33 brd ff:ff:ff:ff:ff:ff link-netnsid 0
通过如下命令可以查看test namespace的网口,发现刚刚不见了的veth1。说明veth1已经加入test namespace中。
[root@centos-7 ~]# ip netns exec test ip link list
1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1@if6:
link/ether 7a:51:22:e3:a6:15 brd ff:ff:ff:ff:ff:ff link-netnsid 0
配置test Namespace的网口。可以通过ip netns exec进行配置。
[root@centos-7 ~]# ip netns exec test ifconfig veth1 172.16.0.2/16 up
[root@centos-7 ~]# ip netns exec test ifconfig
veth1: flags=4099
inet 172.16.0.2 netmask 255.255.0.0 broadcast 172.16.255.255
ether 7a:51:22:e3:a6:15 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
这样一个隔离的容器网络就完成了,又该如何实现容器网络与外部的通信呢?这就需要用到Bridge了。
在默认的Network Namespace"下创建test0网桥:
[root@centos-7 ~]# brctl addbr test0
[root@centos-7 ~]# brctl show
bridge name bridge id STP enabled interfaces
test0 8000.000000000000 no
virbr0 8000.525400b92fbb yes virbr0-nic
test0网桥创建成功,其中docker0是Docker服务器自己的网桥。下一步是给test0分配IP地址并生效,充当Gateway:
[root@centos-7 ~]# ip addr add 172.16.0.1/16 dev test0
[root@centos-7 ~]# ip link set dev test0 up
[root@centos-7 ~]# ifconfig test0
test0: flags=4163
inet 172.16.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::50aa:30ff:fea2:ed27 prefixlen 64 scopeid 0x20
ether 52:aa:30:a2:ed:27 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 25 bytes 3785 (3.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
将veth0"插到"test0 这个Bridge上:
[root@centos-7 ~]# brctl addif test0 veth0
[root@centos-7 ~]# ip link set veth0 up
[root@centos-7 ~]# brctl show test0
bridge name bridge id STP enabled interfaces
test0 8000.a67843742333 no veth0
查看test网络生成了一条直连路由表,现在test网络可以ping通test0了。
[root@centos-7 ~]# ip netns exec test ip route show
172.16.0.0/16 dev veth1 proto kernel scope link src 172.16.0.2
[root@centos-7 ~]# ip netns exec test ping -c 3 172.16.0.1
PING 172.16.0.1 (172.16.0.1) 56(84) bytes of data.
64 bytes from 172.16.0.1: icmp_seq=1 ttl=64 time=0.091 ms
64 bytes from 172.16.0.1: icmp_seq=2 ttl=64 time=0.109 ms
64 bytes from 172.16.0.1: icmp_seq=3 ttl=64 time=0.150 ms
— 172.16.0.1 ping statistics —
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.091/0.116/0.150/0.027 ms
[root@centos-7 ~]# ip netns exec test ping -c 3 172.17.0.1
connect: 网络不可达
但由于没有默认路由,Docker还不能与其他网络相通,通过ping docker0测试发现确实如此。为test网络添加一条默认路由表,测试ping docker0发现成功。
[root@centos-7 ~]# ip netns exec test ip route add default via 172.16.0.1
[root@centos-7 ~]# ip netns exec test ping -c 3 172.17.0.1
PING 172.17.0.1 (172.17.0.1) 56(84) bytes of data.
64 bytes from 172.17.0.1: icmp_seq=1 ttl=64 time=0.091 ms
64 bytes from 172.17.0.1: icmp_seq=2 ttl=64 time=0.109 ms
64 bytes from 172.17.0.1: icmp_seq=3 ttl=64 time=0.150 ms
— 172.17.0.1 ping statistics —
现在的test网络可以与主机相通了,但还不能访问外部网络,因为icmp包回来时找不到目的地,也就找不到172.17.0.2了,可以通过iptables来解决。
[root@centos-7 ~]# ip netns exec test ping -c 3 114.114.114.114
hang住…
[root@centos-7 ~]# iptables -t nat -A POSTROUTING -s 172.16.0.0/16 ! -o test0 -j MASQUERADE
[root@centos-7 ~]# ip netns exec test ping -c 3 114.114.114.114
PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.
64 bytes from 114.114.114.114: icmp_seq=1 ttl=127 time=10.9 ms
64 bytes from 114.114.114.114: icmp_seq=2 ttl=127 time=15.4 ms
64 bytes from 114.114.114.114: icmp_seq=3 ttl=127 time=14.6 ms
— 114.114.114.114 ping statistics —
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 10.923/13.666/15.444/1.972 ms
可以看出添加完iptables规则后已经可以正常访问外网了。这样一个类Docker的网络就完成了,其实Docker的网络相对会比这复杂很多,但基本实现原理方法是一样的。
Iptables的DNAT规则。
[](()三、docker使用
查看命令帮助:docker COMMAND --help
[root@localhost ~]# docker search centos #搜索远程仓库的镜像
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/centos The official build of CentOS. 3939 [OK]
docker.io docker.io/ansible/centos7-ansible Ansible on Centos7 103 [OK]
docker.io docker.io/jdeathe/centos-ssh CentOS-6 6.9 x86_64 / CentOS-7 7.4.1708 x8… 91 [OK]
…
docker search可能搜索到的比较少,例如centos的official分支只有latest版本,如果需要其他版本,可以使用https://hub.docker.com/进行搜索。
Docker镜像命名的规则:镜像仓库地址/用户名(或项目名)/镜像名称:tag标签
;如果镜像仓库地址
缺省,则为dockerhub,即docker.io;如果是私有仓库,一般有用户名或项目名,如果缺省,则为library;如果tag缺省,则为latest。
新版本中,使用docker image ls
.
Docker registry是存储容器镜像的仓库,用户可以通过Docker client与Docker registry进行通信,以此来完成镜像的搜索、下载和 上传等相关操作。Docker Hub是由Docker公司在互联网上提供的一个镜像仓库,提供镜像的公有与私有存储服务,它是用户最主要的镜像来源。除了Docker Hub外,用户还可以自行搭建私有服务器来实现镜像仓库的功能。
格式:docker pull [OPTIONS] NAME[:TAG]
[root@localhost ~]# docker pull docker.io/centos
格式:docker push[OPTIONS] NAME[:TAG]
无论是pull还是push,如果镜像仓库是私有仓库,则需要登录后才能进行相关的操作。
docker login|logout URL
[root@k8s-node01 ~]# docker login registry.cn-qingdao.aliyuncs.com
Username: admin
Password:
docker load -i /path/to/image #-i指定导入的镜像的归档文件
docker save -o /path/to/image image_id
格式:docker run -it REPOSITORY:TAG [COMMAND:-/bin/bash] [ARG]
-i: interactive 交互模式,通常与-t同时使用
-t:terminate 为容器分配一个伪终端
-d:daemon 以后台进程运行
–rm:参数使容器退出之后自动删除,ps -a的时候是不显示的
–name:指定docker run命令运行的容器的名称,如果缺省,Docker将为容器随机分配一个名字
-p:端口映射, 宿主机端口:容器的端口
-v:用于挂载一个volume,将宿主机目录/文件挂载到容器内的某个目录。格式:[host-dir]:[container-dir][:rw|ro]
–volumes-from :卷可以容器间共享和重用
docker run -it -d --rm -p 80:80 --name c1 -v /data/html:/var/share/nginx/html nginx
docker run -it -d --rm -p 80:80 --name c2 --volumes-from c1 nginx
-e:指定环境变量
–link:使用
的格式连接到另一个容器,建立同一台宿主机上容器间的互联。可配置多个,其中name是容器通过–name参数指定或自动生成的名字,如“db” “web" 等,而不是容器的主机名。alias为容器的别名,如本例中的webdb。
docker run -d --name mysql mysql:5.7.20
docker run -d --name web --link mysql:mysql app:lastest
–network 指定网络
–network bridge 缺省默认网络,会自动创建docker0桥,所有容器都会连接到docker0上,并将网关设置为docker0。
–network none 没有网络,只有lo网卡;这种网络一般会在自定义网络的情况下使用。
–network container:CANTAINERNAME 与其他已存在的容器共用一个网络,新创建的容器可以与之前的容器使用localhost进行访问。
–network host 与宿主机共用网络。容器就相当于宿主机上的一个普通进程。
–privileged 为容器提供扩展权限
-m, --memory bytes:内存限制
–cpus decimal:cpu限制
docker start/stop/restart :用于一个已经存在的容器的启动、关闭、重启,可以指定容器id或容器name。
docker ps :默认显示当前正在运行的容器
docker ps -a :显示所有运行过的容器(已分配container id),当前状态可能是运行,也可能是未运行
docker ps -q :–quite,只显示容器ID
新版本中,使用
docker container ls
.
命令格式: docker exec -it
[root@localhost ~]# docker exec -it 1592daced897 /bin/bash
删除容器:docker rm CONTAINERID [CONTAINERID…]
删除所有的容器:docker rm $(docker ps -a -q)
删除镜像:docker rmi IMAGE [IMAGE…]
docker commit命令可以将一个容器固化为一个新的镜像。当需要制作特定的镜像时,会进行修改容器的配置,如在容器中安装特定工具等,通过commit命令可以将这些修改保存起来,使其不会因为容器的停止而丢失。
使用方法如下:
docker commit [OPTIONS] CONTAINER [REPOSITORY[ :TAG]]
提交保存时,只能选用正在运行的容器(即可以通过docker ps查看到的容器)来制作新的镜像。在制作特定镜像时,直接使用commit命令只是一个临时性的辅助命令,不推荐使用。官方建议通过docker build命令结合Dockerfile创建和管理镜像。
docker inspect命令可以查看镜像和容器的详细信息,默认会列出全部信息,可以通过–format参数来指定输出的模板格式,以便输出特定信息。
使用方法如下:
docker inspect [OPTIONS] CONTAINER| IMAGE [CONTAINER | IMAGE...]
#查看容器的内部IP
docker inspect --format=‘{{.NetworkSettings.IPAddress}}’ ee36
172.17.0.8
#查看容器卷
docker inspect --format “{{.Volumes}}” bc8e
使用方法:
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
[](()☆☆☆、容器使用建议:
1、docker容器的日志全部输出到控制台。
2、应用做健康监测的接口。
3、如果使用服务器文件系统目录,要使用相对目录。尤其不要出现windows目录,例如e:\myapp\upload
4、接上例。如果应用运行过程中,会在服务器上产生数据文件(并非临时文件)。例如用户上传的附件等。这些操作一定要通知运维。因为默认数据全部放在数据中心里(mysql、oss等),如果存放在服务器上,需要对这些文件进行备份处理,以免丢失数据。尤其是docker运行的情况下。
[](()四、Dockefile指令
井号开头的行为注释行。
非井号开头的行为指令行,指令是不区分大小写的,但是建议指令使用大写。
Dockerfile文件中的第一个非指令行必须为FROM指令,用于指定构建镜像使用的基础镜像。
FROM openjdk:8u201-jdk-alpine3.9
#Alpine系统设置
RUN echo http://mirrors.aliyun.com/alpine/v3.9/main > /etc/apk/repositories && \
echo http://mirrors.aliyun.com/alpine/v3.9/community >> /etc/apk/repositories && \
#时区设置
apk -U --no-cache add tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
#添加系统字体(ttf-dejavu)、字体管理软件(fontconfig)
apk -U --no-cache add ttf-dejavu fontconfig && \
#其他常用软件
apk -U --no-cache add ca-certificates curl bash
#添加中文字体,前提:已经安装字体管理软件(fontconfig)
COPY chinese /usr/share/fonts/chinese
#设置环境变量
ENV PS1=“[\u@\h \W]$”
#entrypoint脚本
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
#-------------------------------------------------------
#Tomcat相关设置
#-------------------------------------------------------