最后
小编的一位同事在校期间连续三年参加ACM-ICPC竞赛。从参赛开始,原计划每天刷一道算法题,实际上每天有时候不止一题,一年最终完成了 600+:
凭借三年刷题经验,他在校招中很快拿到了各大公司的offer。
入职前,他把他的刷题经验总结成1121页PDF书籍,作为礼物赠送给他的学弟学妹,希望同学们都能在最短时间内掌握校招常见的算法及解题思路。
整本书,我仔细看了一遍,作者非常细心地将常见核心算法题和汇总题拆分为4个章节。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
而对于有时间的同学,作者还给出了他结合众多数据结构算法书籍,挑选出的一千多道题的解题思路和方法,以供有需要的同学慢慢研究。
-
memory: 限制内存的使用.上限。
-
freezer:暂停Cgroup中的进程。
-
net_cls: 配合traffic controller限制网络带宽。
-
net_prio: 可以动态控制每个网卡流量的优先级。
-
blkio: 限制进程的块设备I/O。
-
ns: 使不同Cgroups中的进程使用不同的Namespace。
2、Cgroups的使用
可以使用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
1、什么是UnionFS
UnionFS(联合文件系统)是把不同物理位置的目录合并到同一个目录中的文件系统服务。其早期是应用在LiveCD领域的,通过联合文件系统可以非常快速地引导系统初始化或检测磁盘等硬件资源。这是因为只需要把CD只读挂载到特定目录,然后在其上附加一层可读写的文件层,对文件的任何变动修改都会被添加到新的文件层内,这种技术被称为写时复制。
写时复制是一种可以有效节约资源的技术,它被很好地应用在Docker镜像上。其思想是如果有一个资源需要被重复利用,在没有任何修改的情况下,新旧实例会共享资源,并不需要进行复制,如果有实例需要对资源进行任何的修改,并不会直接修改资源,而是会创建一个新的资源并在其上进行修改,这样原来的资源并不会进行任何修改,而是与新创建的资源结合在外,表现为修改后的资源状态。这样做可以显著地减轻对未修改资源的复制而带来的资源消耗问题。
下面通过讲解在Docker中如何使用UnionFS更深入地理解写时复制。
2、UnionFS在Images中的使用
一个最常见的 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
1、网络原理
这部分主要介绍Docker的网络原理,通过Linux系统模拟实现一个Docker默认网络的方法。
首先对Docker网络的实现原理进行整体简略的介绍,当Docker服务安装并启动后,在主机上输入ifconfig 命令,可以发现主机上多了一个docker0的虚拟网桥,这个网桥为Docker的网络通信提供支持。如图所示,在默认网络情况下,当启动一个Docker容器时,Docker会为容器分配一个IP地址,并通过一对vethpair将容器的eth0绑定到主机的docker0网桥中。
2、模拟实现Docker网络
下面通过Linux系统模拟Docker网络模型,实现上面介绍的网络结构。
- 创建Network Namespace
[root@centos-7 ~]# ip netns add test
[root@centos-7 ~]# ip netns list
test
此时Namespace test 创建成功了,在/var/un/netns 目录中可以看到一个test文件。这个namespace可以理解为是一个docker容器。
当启动一个容器时,Docker 会为容器创建一个Network Namespace,可以看到在/var/run/docker/netns目录下生成一个对应的文件。
- 添加网口到Namespace
先创建veth:
[root@centos-7 ~]# ip link add veth0 type veth peer name veth1
在当前Namespace中可以看到veth0和veth1:
[root@centos-7 ~]# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:1c:42:60:50:ff brd ff:ff:ff:ff:ff:ff
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN mode DEFAULT group default qlen 1000
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
5: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 7a:51:22:e3:a6:15 brd ff:ff:ff:ff:ff:ff
6: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
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: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:1c:42:60:50:ff brd ff:ff:ff:ff:ff:ff
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN mode DEFAULT group default qlen 1000
link/ether 52:54:00:b9:2f:bb brd ff:ff:ff:ff:ff:ff
6: veth0@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
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: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
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<UP,BROADCAST,MULTICAST> mtu 1500
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<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
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的网络相对会比这复杂很多,但基本实现原理方法是一样的。
3、端口映射原理
Iptables的DNAT规则。
docker命令列表
查看命令帮助:docker COMMAND --help
docker search查找镜像
[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 images查看本机已经存在的镜像
新版本中,使用docker image ls
.
docker pull拉取镜像
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推送镜像
格式: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从文件中导入镜像
docker load -i /path/to/image #-i指定导入的镜像的归档文件
docker save将镜像保存为归档文件
docker save -o /path/to/image image_id
docker run 运行镜像,创建容器
格式: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 or id>:alias
的格式连接到另一个容器,建立同一台宿主机上容器间的互联。可配置多个,其中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 启动、关闭、重启容器
docker start/stop/restart :用于一个已经存在的容器的启动、关闭、重启,可以指定容器id或容器name。
docker ps 查看正在运行的容器
docker ps :默认显示当前正在运行的容器
docker ps -a :显示所有运行过的容器(已分配container id),当前状态可能是运行,也可能是未运行
docker ps -q :–quite,只显示容器ID
新版本中,使用
docker container ls
.
docker exec在容器内执行命令
命令格式: docker exec -it <CONTAINER_ID|NAME> COMMAND
[root@localhost ~]# docker exec -it 1592daced897 /bin/bash
docker rm删除容器
删除容器:docker rm CONTAINERID [CONTAINERID…]
删除所有的容器:docker rm $(docker ps -a -q)
docker rmi删除镜像
删除镜像:docker rmi IMAGE [IMAGE…]
docker commit从容器创建一个新的镜像
docker commit命令可以将一个容器固化为一个新的镜像。当需要制作特定的镜像时,会进行修改容器的配置,如在容器中安装特定工具等,通过commit命令可以将这些修改保存起来,使其不会因为容器的停止而丢失。
使用方法如下:
docker commit [OPTIONS] CONTAINER [REPOSITORY[ :TAG]]
提交保存时,只能选用正在运行的容器(即可以通过docker ps查看到的容器)来制作新的镜像。在制作特定镜像时,直接使用commit命令只是一个临时性的辅助命令,不推荐使用。官方建议通过docker build命令结合Dockerfile创建和管理镜像。
docker inspect查看镜像和容器的详细信息
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宿主机、容器文件互拷
使用方法:
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运行的情况下。
Dockerfile说明
-
井号开头的行为注释行。
-
非井号开头的行为指令行,指令是不区分大小写的,但是建议指令使用大写。
-
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相关设置
#-------------------------------------------------------
#设置Tomcat环境变量
ARG TOMCAT_VERSION=“8.5.56”
ENV TOMCAT_VERSION=${TOMCAT_VERSION} \
CATALINA_HOME=“/usr/local/tomcat” \
CLASSPATH=“.: J A V A H O M E / l i b : JAVA_HOME/lib: JAVAHOME/lib:JAVA_HOME/jre/lib”
ENV PATH=“ C A T A L I N A H O M E / b i n : {CATALINA_HOME}/bin: CATALINAHOME/bin:PATH”
#安装tomcat
ADD https://mirrors.aliyun.com/apache/tomcat/tomcat-8/v T O M C A T V E R S I O N / b i n / a p a c h e − t o m c a t − {TOMCAT_VERSION}/bin/apache-tomcat- TOMCATVERSION/bin/apache−tomcat−{TOMCAT_VERSION}.tar.gz /usr/local
RUN set -ex; \
tar xf /usr/local/apache-tomcat-${TOMCAT_VERSION}.tar.gz -C /usr/local/ && \
mv /usr/local/apache-tomcat-${TOMCAT_VERSION} ${CATALINA_HOME} && \
rm -rf C A T A L I N A H O M E / w e b a p p s / ∗ / u s r / l o c a l / a p a c h e − t o m c a t − {CATALINA_HOME}/webapps/* /usr/local/apache-tomcat- CATALINAHOME/webapps/∗/usr/local/apache−tomcat−{TOMCAT_VERSION}.tar.gz
#启动入口
ENTRYPOINT [“docker-entrypoint.sh”]
EXPOSE 8080
WORKDIR $CATALINA_HOME
CMD [“catalina.sh”, “run”]
#-------------------------------------------------------
#运行应用相关Dockerfile
#-------------------------------------------------------
FROM registry.cn-qingdao.aliyuncs.com/rcyj/tomcat:8.5.54-openjdk8u201-alpine3.9
LABEL maintainer lijuzhanglijuzhang@rlzbcy.com
#导入应用
ADD *.war ${CATALINA_HOME}/webapps/ROOT.war
FROM
FROM指令是最重的一个且必须为Dockerfile文件开篇的第一个非注释行,用于为image构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境
实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件。如果找不到指定的镜像文件,dockerbuild会返回一个错误信息
语法:
FROM [:]
或
FROM @]
说明:
: 指定作为base image的名称;
: base image的标签,为可选项,省略时默认为latest;
最佳实践:
1、尽可能使用当前官方仓库作为你构建镜像的基础。推荐使用 Alpine 镜像,因为它被严格控制并保持最小尺寸(5MB左右),但它仍然是一个完整的发行版。
2、可以使用多阶段构建
FROM centos:7.5.1804 as base
…
…
#多阶段构建
from centos:7.5.1804
COPY --from=base /usr/local/jdk* $JAVA_HOME/
MAINTANIER(已废弃)
MAINTANIER (depreacted),使用LABEL代替。
用于让Dockerfile制作者提供本人的详细信息
Dockerfile并不限制MAINTAINER指令可在出现的位置,但推荐将其放置于FROM指令之后
语法:
MAINTAINER <authtor's detail>
-
<author’s detail>可是任何文本信息,但约定俗成地使用作者名称及邮件地址
-
MAINTAINER " <mage@magedu.com>"
LABEL
LABEL指令将元数据添加到图像。你可以给镜像添加标签来帮助组织镜像、记录许可信息、辅助自动化构建等。
语法:
LABEL <key>=<value> <key>=<value>...
一个LABEL是一个key-value对,如果你的字符串中包含空格,必须将字符串放入引号中或者对空格使用反斜线转义。如果字符串内容本身就包含引号,必须对引号使用转义。
一个image可以有多个LABEL,也可以在一行中指定多个LABEL.
Set one or more individual labels
LABEL com.example.version=“0.0.1-beta”
LABEL vendor=“ACME Incorporated”
LABEL com.example.release-date=“2015-02-12”
LABEL com.example.version.is-production=“”
一个镜像可以包含多个标签,但建议将多个标签放入到一个 LABEL
指令中。
Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \
com.example.is-production=“” \
com.example.version=“0.0.1-beta” \
com.example.release-date=“2015-02-12”
RUN
用于指定docker build过程中运行的程序,其可以是任何命令
语法:
RUN <command>
或
RUN ["<executable>", "<param1>", "<param2>"]
-
第一种格式中,
<command>
通常是一个shell命令, 且以"/bin/sh -c"
来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>
命令停止容器时,此进程接收不到SIGTERM信号; -
第二种语法格式中的参数是一个JSON格式的数组,其中
<executable>
为要运行的命令,后面<paramN>
为传递给命令的选项或参数;然而,此种格式指定的命令不会以"/bin/sh -c"
来发起,因此*常见的shell操作如变量替换以及通配符(?,等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。RUN ["/bin/bash", "-c", "<executable>", "<param1>"]
。注意: json数组中, 要使用双引号 -
为了保持
Dockerfile
文件的可读性,可理解性,以及可维护性,建议将长的或复杂的RUN
指令用反斜杠\
分割成多行。
FROM alpine:3.9
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
centos安装软件的最佳实践:
react和vue的比较
相同
1)vitual dom
2)组件化
3)props,单一数据流
不同点
1)react是jsx和模板;(jsx可以进行更多的js逻辑和操作)
2)状态管理(react)
3)对象属性(vue)
4)vue:view——medol之间双向绑定
5)vue:组件之间的通信(props,callback,emit)
第一种格式中,<command>
通常是一个shell命令, 且以"/bin/sh -c"
来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>
命令停止容器时,此进程接收不到SIGTERM信号;
-
第二种语法格式中的参数是一个JSON格式的数组,其中
<executable>
为要运行的命令,后面<paramN>
为传递给命令的选项或参数;然而,此种格式指定的命令不会以"/bin/sh -c"
来发起,因此*常见的shell操作如变量替换以及通配符(?,等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。RUN ["/bin/bash", "-c", "<executable>", "<param1>"]
。注意: json数组中, 要使用双引号 -
为了保持
Dockerfile
文件的可读性,可理解性,以及可维护性,建议将长的或复杂的RUN
指令用反斜杠\
分割成多行。
FROM alpine:3.9
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
centos安装软件的最佳实践:
react和vue的比较
相同
1)vitual dom
2)组件化
3)props,单一数据流
不同点
1)react是jsx和模板;(jsx可以进行更多的js逻辑和操作)
2)状态管理(react)
3)对象属性(vue)
4)vue:view——medol之间双向绑定
5)vue:组件之间的通信(props,callback,emit)
[外链图片转存中…(img-fYogTOSi-1715420256422)]
[外链图片转存中…(img-Y6SgfmAA-1715420256422)]