Docker 最核心的组件
- image镜像:构建容器(我们将应用程序以及运行环境打包为镜像环境)
- Container:容器(应用程序就跑在容器中)
- 镜像仓库:保存镜像文件、上传和下载镜像
- Dockerfile:将部署的操作写成脚本
docker ps 查看当前正在执行的容器:docker ps,当然如果现在执行什么都不会显示,因为我们还没有任何容器; docker ps -a 查看当前所有容器(包括正在执行的和已经结束的):docker ps -a,同样,现在执行,我们也不会看到任何结果; docker images 查看本地已经安装的docker镜像:docker images;
docker run ubuntu:latest ls -l 执行一个ubuntu 18.04容器
容器里究竟有些什么东西
docker inspect 这个命令需要接受一个容器ID或者NAME作为参数 返回的是: 这是一个JSON对象,包含了一个容器的全部内容。当然我们没必要逐一去讲每一个字段的含义,大家在终端里执行一下,然后自己去看看就好
两种访问inspect结果的方法
docker inspect原生支持的,它有一个-f参数,允许我们用go template的语法选择要使用的JSON字段。
例如,为了读取容器IP地址字段,我们可以这样
docker inspect -f {{.NetworkSettings.IPAddress}} 38867a291e60
jq stedolan.github.io/jq/ 它是一个很方便的基于命令行的JSON parser,我们直接执行brew install jq安装
docker inspect 1769e51eba1a | jq
可以看到,之前黑白的JSON结果变成彩色的了。并且,和docker inspect的-f参数类似,它接受一个-r参数也可以让我们访问指定的字段,例如之前的访问IP地址,现在可以这样: ocker inspect 7b479ec00c26 | jq -r ".[0].NetworkSettings.IPAddress"
为了读取容器IP地址字段,我们可以这样: docker inspect -f {{•NetworkSettings .IPAddress}} 176951ebala(id或者name)
docker inspect 7b479ec00c26(id或者name)
[
{
"Id": "7b479ec00c2624ac95911afb802629fc40000a9ae699881ed9d0828eb5824565",
"Created": "2023-02-22T08:36:19.565910637Z",
"Path": "ls",
"Args": [
"-l"
],
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-02-22T08:36:19.881681804Z",
"FinishedAt": "2023-02-22T08:36:19.882245971Z"
},
"Image": "sha256:a6be1f66f70f66ef43503292e38ccbfc14f2d5464e7736344783a8fc7bb339a8",
"ResolvConfPath": "/var/lib/docker/containers/7b479ec00c2624ac95911afb802629fc40000a9ae699881ed9d0828eb5824565/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/7b479ec00c2624ac95911afb802629fc40000a9ae699881ed9d0828eb5824565/hostname",
"HostsPath": "/var/lib/docker/containers/7b479ec00c2624ac95911afb802629fc40000a9ae699881ed9d0828eb5824565/hosts",
"LogPath": "/var/lib/docker/containers/7b479ec00c2624ac95911afb802629fc40000a9ae699881ed9d0828eb5824565/7b479ec00c2624ac95911afb802629fc40000a9ae699881ed9d0828eb5824565-json.log",
"Name": "/brave_stonebraker",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "private",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": null,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/ff9d0606845be43930e06b60620dd038a8eb9f8ac9a296bcda715823408276e5-init/diff:/var/lib/docker/overlay2/e14ea635896b3a2d25206bc250d75300b3f7d6d4fe8fe538dc9ee2204365cd66/diff",
"MergedDir": "/var/lib/docker/overlay2/ff9d0606845be43930e06b60620dd038a8eb9f8ac9a296bcda715823408276e5/merged",
"UpperDir": "/var/lib/docker/overlay2/ff9d0606845be43930e06b60620dd038a8eb9f8ac9a296bcda715823408276e5/diff",
"WorkDir": "/var/lib/docker/overlay2/ff9d0606845be43930e06b60620dd038a8eb9f8ac9a296bcda715823408276e5/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "7b479ec00c26",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"ls",
"-l"
],
"Image": "ubuntu:latest",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "22.04"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "8331d4e6a11f85ae953e74328ea83d1d380424396be8a5f590a7a0a4d4e7b99c",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/8331d4e6a11f",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "3fa9b590b9d65f2616ef531808647648f599792ae50cbb159f1b004ba3cba3d7",
"EndpointID": "",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
}
}
]
清理和容器有关的资源
如何删除容器 docker rm a243dd60b793 容器的ID docker rm priceless_hugle 容器的名字
清除容器列表 docker rm $(docker ps -a -q) 这里,-q是让docker ps命令只显示容器ID列表。我们也可以把-a -q写成-aq
每次执行完一个容器之后还要记得删掉很麻烦啊,能不能执行完就自动删掉呢? docker run --rm ubuntu:latest ls -l
如何删除镜像 docker rmi ubuntu:latest 使用name:tag的形式来指定镜像 按照容器ID来删除 docker rmi $(docker images -q)
如何与容器交互
为了能和容器里这个bash交互 docker run -i -t ubuntu:latest bash
- -i是interactive,表示我们要和容器交互;
- -t是tty,让docker创建一个虚拟终端,这样我们就能在屏幕上看到来自容器的控制台输出了;
除了正在打印消息的ps aux进程外,整个容器里只有一个bash进程。这是容器区别于虚拟机最明显的一个地方,容器就像一个沙箱一样,把进程隔离在容器里,而进程本身对此却不知情,以为自己就是这个操作系统中的唯一进程。
接下来,要退出这个容器,我们只要执行exit离开bash就好了
恢复已经结束的容器
我们再想在容器中执行bash的时候,除了使用docker run新启动一个容器之外,还可以重新启动之前退出的容器。例如,我们执行: docker start c7559a4d6165
交互模式重启 docker start -i c7559a4d6165
可以用docker stop ID停止一个在后台执行的容器; 可以用-i参数以交互模式恢复容器的执行;
通过容器启动一个Nginx server
基于上一节的结果,我们以交互模式启动一个执行bash的容器:docker run -i -t ubuntu:latest bash。接下来,用起来就和普通的Ubuntu一样了,我们先在Shell中执行下面的命令安装一下Nginx
apt-get update && apt-get install -y nginx
安装完成后,和普通的Ubuntu不同的是,Nginx不会自动启动,我们需要手工执行一下nginx命令。然后,当我们执行ps aux的时候,就会看到Nginx启动了
通过host访问容器中的Web服务
另起一终端 查看容器的IP地址 docker inspect c7559a4d6165 | jq -r ".[0].NetworkSettings.IPAddress"
由于是个容器需要把其端口映射到外面进行访问,Nginx的80端口是开放在容器内的 docker run -it -p 8080:80 ubuntu:latest bash
-p参数可以让我们用host_port:container_port的格式指定容器内外的端口映射规则
通过Volumn共享文件
最好的办法,则是可以像端口映射一样,把Host上的某个目录映射到容器里。为此,我们可以在启动容器的时候,使用-v参数
由于容器中的Nginx默认的web根目录是/var/www/html,最简单的,我们把这个目录映射出来就好了。
首先,在host中,创建一个/Myweb目录,并在其中添加一个demo.html文件
docker run -it -p 8080:80 -v /Myweb:/var/www/html ubuntu:latest bash
我们使用了-v host_dir:container_dir进行了目录映射。映射之后,在容器中,之前/var/www/html目录指定的内容就无法访问了。现在/var/www/html访问的,是host上的/tmp/web目录。
实际上,我们也可以用这样的方式给容器添加多个目录映射,只要使用多个-v参数就好了
构建自己的docker镜像
执行docker diff 9c961bfe148a
可以看到,Docker用类似git的形式记录了容器中的每一个文件变化。并且,我们还可以像Git中提交代码一样,去提交这些变化。在终端中,我们执行:
docker commit -a "bbb" -m "Install Nginx" 42f4ea144b73 lll/nginx:0.1.0
-a表示Author,即提交者的姓名; -m表示Message,即本次提交的注释; 42f4ea144b52,这是容器ID,它表示了我们要制作的镜像最终的状态; lll/nginx:0.1.0,这是新镜像的名称,以及版本号;