1、Web应用运行和访问实例
1.1 运行一个Web应用
直接在docker中search一个webapp镜像即可,无需自己写。
docker search webapp
pull一个webapp: 【这个测试webapp国内网络下载速度可能较慢】
docker pull training/webapp
下载完后,接着启动这个webapp:
docker run -d -P training/webapp python app.py
参数说明:
- -d:让容器在后台运行。
- -P:将容器内部使用的网络端口映射到我们使用的主机上。
1.2 访问App
注意看上图PORTS部分为0.0.0.0:49153->5000/tcp。
Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 49153 上。
从主机上看,它应该暴露了端口49153:
验证如下:
netstat | grep 32768
netstat -nltp | grep 32768
curl localhost:32768
从容器内部看,它应该有一个端口5000:
验证如下:
docker exec -it d646216dd513 /bin/bash
netstat -nltp
1.3 设置自定义映射端口
通过 -P参数映射到主机上的端口是随机的。可以通过 -p 参数来设置不一样的端口。
docker run -d -p 5001:5000 training/webapp python app.py
docker ps
netstat -nltp | grep 5001
curl localhost:5001
从上图中可以看到,容器中跑了两个内部端口都是5000的web实例。新的容器内部的 5000 端口映射到我们本地主机的 5001 端口上。
2、常用的功能
2.1 查看web应用网络端口
通过 docker ps 命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port,使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。
docker port d646216dd513
2.2 查看web应用程序日志
docker logs [ID或者名字] 可以查看容器内部的标准输出。
docker logs -f 4697fd8148a3
参数说明:
- -f: 让 docker logs 像使用 tail -f 一样来输出容器内部的标准输出。
2.3 查看web应用程序容器的进程
可以使用 docker top 来查看容器内部运行的进程。
docker top 4697fd8148a3
2.4 检查web应用程序
使用 docker inspect 来查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。
docker inspect 4697fd8148a3
[root@192 keepmoving]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4697fd8148a3 training/webapp "python app.py" 15 minutes ago Up 15 minutes 0.0.0.0:5001->5000/tcp, :::5001->5000/tcp friendly_jennings
d646216dd513 training/webapp "python app.py" 31 minutes ago Up 31 minutes 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp funny_hodgkin
[root@192 keepmoving]# docker inspect 4697fd8148a3
[
{
"Id": "4697fd8148a35a5eafc5051df0ab220545c6230bc78fcddfb8fe7609ef3527a9",
"Created": "2023-02-24T16:17:48.919718603Z",
"Path": "python",
"Args": [
"app.py"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 7726,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-02-24T16:17:49.212901136Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557",
"ResolvConfPath": "/var/lib/docker/containers/4697fd8148a35a5eafc5051df0ab220545c6230bc78fcddfb8fe7609ef3527a9/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/4697fd8148a35a5eafc5051df0ab220545c6230bc78fcddfb8fe7609ef3527a9/hostname",
"HostsPath": "/var/lib/docker/containers/4697fd8148a35a5eafc5051df0ab220545c6230bc78fcddfb8fe7609ef3527a9/hosts",
"LogPath": "/var/lib/docker/containers/4697fd8148a35a5eafc5051df0ab220545c6230bc78fcddfb8fe7609ef3527a9/4697fd8148a35a5eafc5051df0ab220545c6230bc78fcddfb8fe7609ef3527a9-json.log",
"Name": "/friendly_jennings",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"5000/tcp": [
{
"HostIp": "",
"HostPort": "5001"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"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": false,
"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/62abe074323b2620f26c6965087bcbe21e56e54497e913669f8c0bd41aa3f14c-init/diff:/var/lib/docker/overlay2/3f0811533dfca9363e7150c6a7592500b9f93e1e1666a90d329f1af8f13dfb8c/diff:/var/lib/docker/overlay2/437bdf36dee06f6619a5f1bee660c747cc556e851f613e1158afc96165b18615/diff:/var/lib/docker/overlay2/d1b034ca7319ee0928aaafde86b2aeaa13ec77eeb9d671af2c96de2ba244957d/diff:/var/lib/docker/overlay2/1ccbd811e55023283fbce1e2e8b04f55851986779b69f0089026569968700595/diff:/var/lib/docker/overlay2/6e9fe1298d1eb253e7289d372afaee9bc6a637ace6d569102e371c8f9f955cb8/diff:/var/lib/docker/overlay2/34387ef5b499b54fba4d444174e22a40ad885e6adc5054347fa37e10a73f84bc/diff:/var/lib/docker/overlay2/59958dfb13ab73cc947c52534550ee93092b0dea4011d7fe74549d160a069abc/diff:/var/lib/docker/overlay2/951d10b2d3212cbdd7323b25b1c3c5e3380a1f18e09b8e566b2a43a96cd00323/diff:/var/lib/docker/overlay2/cd2891ea16adcb3d6d31056755835bf9cec806eb06d42d4c29ff2e88f680d395/diff:/var/lib/docker/overlay2/ac9857dff6507ea4f5aa187c2b443eb6de09676f52e8857d116b97e463a16c2e/diff:/var/lib/docker/overlay2/fde236b9e764cf4ee565ceba0f1fc99efc16ba60b4a4f7d2723622a40d526557/diff:/var/lib/docker/overlay2/85b19f3ebf6a41781e5982b655803dabffc9c8ac85bd6ee1a4026c46925d364e/diff:/var/lib/docker/overlay2/49762ef50589e5bf5bfcf0fe57b3b8bd16c60e9ce6ff62253408f345bff6f38e/diff",
"MergedDir": "/var/lib/docker/overlay2/62abe074323b2620f26c6965087bcbe21e56e54497e913669f8c0bd41aa3f14c/merged",
"UpperDir": "/var/lib/docker/overlay2/62abe074323b2620f26c6965087bcbe21e56e54497e913669f8c0bd41aa3f14c/diff",
"WorkDir": "/var/lib/docker/overlay2/62abe074323b2620f26c6965087bcbe21e56e54497e913669f8c0bd41aa3f14c/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "4697fd8148a3",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"5000/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"python",
"app.py"
],
"Image": "training/webapp",
"Volumes": null,
"WorkingDir": "/opt/webapp",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "836893de8ce73e280874f63b3ee2db5340b788723aa3ff835a6222c641aa7c40",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"5000/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "5001"
},
{
"HostIp": "::",
"HostPort": "5001"
}
]
},
"SandboxKey": "/var/run/docker/netns/836893de8ce7",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "05992053611e52bf08f2a7b420a0f63eff9eddeaff81cbd1ee9e52ea31a64ebb",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "581adbbf78d32412c411c274bb65c339f496b24e9cef5ad69f8d038bcc371c1b",
"EndpointID": "05992053611e52bf08f2a7b420a0f63eff9eddeaff81cbd1ee9e52ea31a64ebb",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
]
2.5 停止web应用容器
docker stop 4697fd8148a3
2.6 重启web应用容器
可以使用命令 docker start 或者docker restart 来启动。
docker restart 4697fd8148a3
2.7 移除web应用程序
- 使用 docker rm 命令来删除不需要的容器。
- 如果是启动着的docker实例,需要加-f,强制(force)删除。
docker rm -f d646216dd513
3、与其它容器(DB容器)互联
上述是一个web单一容器通过端口映射,可以通过主机端口访问容器;那么如果需要访问数据库,就涉及到容器互联。
3.1 与数据库容器互联
创建一个新的数据库容器:
docker search training/postgres
docker run -d --name test_db training/postgre
docker ps
db容器和web容器建立互联关系:
docker run -d -p 5001:5000 --name web --link test_db:test_db training/webapp python app.py
--link 参数的格式为 --link name:alias,其中 name 是要链接的容器的名称,alias 是这个连接的别名。
Docker 在两个互联的容器之间创建了一个安全隧道,而且不用映射它们的端口到宿主主机上。在启动 db 容器的时候并没有使用 -p 和 -P 标记,从而避免了暴露数据库端口到外部网络上。
3.2 容器公开的连接信息
Docker 通过 2 种方式为容器公开连接信息:
- 环境变量
- 更新 /etc/hosts 文件
1.环境变量
使用 env 命令来查看 web 容器的环境变量。
[root@192 keepmoving]# docker exec -it web /bin/bash
root@73a026235a47:/opt/webapp# env
TEST_DB_PORT=tcp://172.17.0.2:5432
HOSTNAME=73a026235a47
TERM=xterm
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
TEST_DB_PORT_5432_TCP_PORT=5432
TEST_DB_PORT_5432_TCP_ADDR=172.17.0.2
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/opt/webapp
TEST_DB_NAME=/web/test_db
SHLVL=1
HOME=/root
LESSOPEN=| /usr/bin/lesspipe %s
TEST_DB_PORT_5432_TCP=tcp://172.17.0.2:5432
TEST_DB_PORT_5432_TCP_PROTO=tcp
LESSCLOSE=/usr/bin/lesspipe %s %s
TEST_DB_ENV_PG_VERSION=9.3
_=/usr/bin/env
其中 TEST_DB_ 开头的环境变量是供 web 容器连接 test_db 容器使用,前缀采用大写的连接别名。
2. host文件
除了环境变量,Docker 还添加 host 信息到父容器的 /etc/hosts 的文件。下面是父容器 web 的 hosts 文件。
root@73a026235a47:/opt/webapp# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 test_db 56657ecbb676
172.17.0.3 73a026235a47
这里有 2 个 hosts:
- 172.17.0.2 test_db 56657ecbb676 表示 test_db 容器的 ip, ID和Name
- 172.17.0.3 73a026235a47 表示 web 容器的 ip, ID
可以在 web 容器中使用 ping 命令来测试跟test_db容器的连通性:
用 ping 来测试test_db容器,它会解析成 172.17.0.2。
同样可以ping容器的ip和ID也是可以的。
用户可以链接多个父容器到子容器,比如可以链接多个 web 到 db 容器上。