Python3实现Docker基本管理
一、预备知识
- Docker
- Linux
- Python
1、Docker基本命令
1.1、查看已有的镜像
➜ ~ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 84164b03fa2e 5 weeks ago 456MB
wordpress latest 126aa00ecc0c 5 weeks ago 540MB
kennethreitz/httpbin latest b138b9264903 17 months ago 534MB
1.2、查看已创建的容器
➜ ~ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8163d8d1e277 wordpress:latest "docker-entrypoint.s…" 3 weeks ago Exited (255) 5 minutes ago 0.0.0.0:8001->80/tcp wordpress
2f23a0ef7add mysql:5.7 "docker-entrypoint.s…" 3 weeks ago Exited (255) 5 minutes ago 0.0.0.0:3306->3306/tcp, 33060/tcp db.wordpress
1c70a141029c kennethreitz/httpbin "gunicorn -b 0.0.0.0…" 4 weeks ago Exited (255) 5 minutes ago 0.0.0.0:80->80/tcp httpbin
1.3、查看正在运行的容器的CONTAINER ID
➜ ~ docker ps -q
1c70a141029c
1.4、启动一个容器
#docker start container_id
➜ ~ docker start 1c70a141029c
1c70a141029c
1.5、关闭一个容器
#docker stop container_id
➜ ~ docker stop 1c70a141029c
1c70a141029c
1.6、重启一个容器
#docker restart container_id
➜ ~ docker restart 1c70a141029c
1c70a141029c
1.7、查看一个容器的详细信息
#docker inspect container_id
➜ ~ docker inspect 1c70a141029c
[
{
"Id": "1c70a141029c02e94cc88fcd3ef9f8bbdb648331765c24709abf9448df8d282a",
"Created": "2020-03-09T15:37:42.352346164Z",
"Path": "gunicorn",
"Args": [
"-b",
"0.0.0.0:80",
"httpbin:app",
"-k",
"gevent"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 3829,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-04-08T23:29:38.049792725Z",
"FinishedAt": "2020-04-08T23:29:37.29916778Z"
},
"Image": "sha256:b138b9264903f46a43e1c750e07dc06f5d2a1bd5d51f37fb185bc608f61090dd",
"ResolvConfPath": "/var/lib/docker/containers/1c70a141029c02e94cc88fcd3ef9f8bbdb648331765c24709abf9448df8d282a/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/1c70a141029c02e94cc88fcd3ef9f8bbdb648331765c24709abf9448df8d282a/hostname",
"HostsPath": "/var/lib/docker/containers/1c70a141029c02e94cc88fcd3ef9f8bbdb648331765c24709abf9448df8d282a/hosts",
"LogPath": "/var/lib/docker/containers/1c70a141029c02e94cc88fcd3ef9f8bbdb648331765c24709abf9448df8d282a/1c70a141029c02e94cc88fcd3ef9f8bbdb648331765c24709abf9448df8d282a-json.log",
"Name": "/httpbin",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"80/tcp": [
{
"HostIp": "",
"HostPort": "80"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "shareable",
"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,
"DiskQuota": 0,
"KernelMemory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/asound",
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/3bfff4d0957fa767bbf9a87564ac5aab092cbf0c4a3d454670d5f41730217b29-init/diff:/var/lib/docker/overlay2/7024e644c3cff797ddf664853271c501ca3153c700aa97183d8f11eb80ecb868/diff:/var/lib/docker/overlay2/05179366f7391597f28b1374de7f309939f924de7fdf759ce44af5f6345c5ca2/diff:/var/lib/docker/overlay2/e312ea37ad0b82784b3dc2432afe8006c138153264ffbb0b9494751edff96894/diff:/var/lib/docker/overlay2/5d6b92d36705697b6b65a5f82201f30c4f1ea8d73420f06869b0ba4120ed023d/diff:/var/lib/docker/overlay2/811021bd290cb003ed2e6b74b133354bbbea68acd198af64e10b09db5e63853d/diff:/var/lib/docker/overlay2/a63a3f457b76c1cb0c052a5dda2a8db2364975e8f89f1bae56d69fda57bdb8b4/diff:/var/lib/docker/overlay2/95b71e3f4a74b2924f402843f6ee47b86605ea86981eceff8ed3e2e987dd9824/diff",
"MergedDir": "/var/lib/docker/overlay2/3bfff4d0957fa767bbf9a87564ac5aab092cbf0c4a3d454670d5f41730217b29/merged",
"UpperDir": "/var/lib/docker/overlay2/3bfff4d0957fa767bbf9a87564ac5aab092cbf0c4a3d454670d5f41730217b29/diff",
"WorkDir": "/var/lib/docker/overlay2/3bfff4d0957fa767bbf9a87564ac5aab092cbf0c4a3d454670d5f41730217b29/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "1c70a141029c",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"80/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"gunicorn",
"-b",
"0.0.0.0:80",
"httpbin:app",
"-k",
"gevent"
],
"ArgsEscaped": true,
"Image": "kennethreitz/httpbin",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"description": "A simple HTTP service.",
"name": "httpbin",
"org.kennethreitz.vendor": "Kenneth Reitz",
"version": "0.9.2"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "d52a556de3d8482e4ad7f6885edff5526a4edd685b6139a65f4a077e0523cace",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "80"
}
]
},
"SandboxKey": "/var/run/docker/netns/d52a556de3d8",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "36bbb91a9b616841e6120477b6b5c6068cccc7a9f0e3390dc7529e98851f6bec",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "dd6a0257d3dcbeb0e97e4d8095274769be43580bfa72fcd6082a9f53f3c91b1d",
"EndpointID": "36bbb91a9b616841e6120477b6b5c6068cccc7a9f0e3390dc7529e98851f6bec",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
1.8、查看正在运行的容器的IP地址(或所有)
1.8.1、第一种方式
#docker inspect --format '{{ .NetworkSettings.IPAddress }}' container_id
~ docker inspect --format '{{ .NetworkSettings.IPAddress }}' 1c70a141029c
172.17.0.2
#这里其实是docker inspect 的一种属性查询,从NetworkSettings找到IPAddress这个属性即可
1.8.2、第二种方式
➜ ~ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 1c70a141029c
172.17.0.2
1.8.、第三种方式
#这里借用Linux系统命令将docker inspect的信息作为输入来进行处理,不会的命令可以看Linux基本命令这一节
➜ ~ docker inspect 1c70a141029c | grep "IPAddress" | tail -n 1| awk -F ':' '{print $2}' | cut -b 3-12
172.17.0.2
1.8.4、查看所有正在运行的容器的IP地址
➜ ~ docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)
/wordpress - 172.17.0.4
/db.wordpress - 172.17.0.3
/httpbin - 172.17.0.2
1.9、查看容器映射的端口
1.9.1、第一种方式
#docker port 与docker container port命令执行起来得到的结果一样
➜ ~ docker port 2f23a0ef7add
3306/tcp -> 0.0.0.0:3306
1.9.2、第二种方式
#这样可以直接看到正在映射过去的端口,缺点是无法看到映射前的端口
➜ ~ docker inspect 2f23a0ef7add | grep HostPort | head -n 1 | awk -F ':' '{print$2}' | awk -F ' ' '{print $1}' | sed $'s/\"//g'
3306
1.10、查看容器的名称
1.10.1、查看正在运行的的容器的名称
➜ ~ docker ps -a | grep "Up" | awk -F " " '{print $NF}' | grep -v NAMES
httpbin
1.10.2、查看所有的容器的名称
➜ ~ docker ps -a | grep "" | awk -F " " '{print $NF}' | grep -v NAMES
wordpress
db.wordpress
httpbin
2、Linux基本命令
2.1、|
“命令格式:命令A|命令B,即命令1的正确输出作为命令B的操作对象”
比如说:
docker inspect container_id | grep "IPAddress"
#将前面查看container_id的具体信息作为输入条件,grep命令在输入的具体信息中寻找与"IPAddress"有关的内容
2.2、grep
grep命令的常用格式为:grep [选项] ”模式“ [文件],在本文中用不到[选项]这个内容。这个命令的意思是在文件中寻找与模式相匹配的内容。
比如说:
➜ ~ grep "IPAddress" info.txt
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.3",
"IPAddress": "172.17.0.3",
#在info.txt这个文件中找到与"IPAddress"相匹配的内容并将其打印出来
2.3、awk
awk命令比较复杂,这里只说与本文有关内容。
这里使用例子:awk -F " " '{print $NF}'
,将前面的输出作为输入进行处理,使用” “(空格)作为分割符,打印最后一列,其中 $NF
代表最后一列,$1
代表第一列,依次往后推
2.4、sed
sed命令比较复杂,这里只说与本文有关内容。
这里使用例子 sed $'s/\"//g'
,这里s/
代表搜索,\
表示转义,也就是说将 "
(双引号)进行转义,然后/
表示格式,/g
表示全局搜索,而两个/
中间没有内容表示空,所以整个语句的意思就是说把双引号去除。
2.5、cut
cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。
这里使用例子:cut -b 3-12"
,-b
表示以字节为单位进行分割。输出第3个到第12个中间的内容
3、Python常用库
3.1、subprocess
subprocess模块中的 getoutput
这个函数可以接受Linux命令执行后返回的结果。
比如说:
>>> import subprocess
>>> s = subprocess.getoutput('cat /etc/issue')
>>> s
'Ubuntu 16.04.6 LTS \\n \\l\n'
#这使得命令返回的结果更容易被处理
3.2、time
time模块中的sleep
函数可以让程序等待指定的时间。
二、代码清单
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# --author:valecalida--
# Edit time: 2020/3/17 19:39
"""代码简陋,大佬勿喷"""
from subprocess import getoutput as shell
import sys, time
total_docker_id = "docker ps -a -q"
unalive_docker_id = "docker ps -a | grep Exited | awk -F ' ' '{print $1}' "
unalive_docker_name = "docker ps -a | grep Exited | awk -F ' ' '{print $NF}'"
alive_docker_id = "docker ps -q"
get_name_part1 = "docker ps -a | grep "
get_name_part2 = " | awk -F ' ' '{print $NF}' | grep -v NAMES"
get_ip_part1 = "docker inspect "
get_ip_part2 = " | grep 'IPAddress' | tail -n 1 | awk -F ':' '{print $2}' | cut -b 3-12"
get_port = " | grep HostPort | head -n 1 | awk -F ':' '{print$2}' | awk -F ' ' '{print $1}' | sed $'s/\"//g'"
start_ins = "docker start "
stop_ins = "docker stop "
def alive_instance_info():
"""这是当前存活的实例的个数"""
alive_instances = shell(alive_docker_id).split('\n')
return alive_instances, len(alive_instances)
def get_alive_instances_infos():
"""显示当前正在运行的docker实例"""
containers_id, _ = alive_instance_info()
containers, containers_ip, containers_name, containers_port, ins_code = [], [], [], [], []
for i in containers_id:
containers_name.append(shell(get_name_part1 + str(i) + get_name_part2))
containers_ip.append(shell(get_ip_part1 + str(i) + get_ip_part2))
containers_port.append(shell(get_ip_part1 + str(i) + get_port))
for k in range(len(containers_id)):
containers.append([str(k + 1), containers_id[k], containers_name[k], containers_ip[k], containers_port[k]])
ins_code.append(k + 1)
return containers, ins_code
def show_alive_instance():
containers, _ = get_alive_instances_infos()
print("\tNow,the instances running are list as follows: ")
print("\t\t实例编号\t容器的ID\t\t容器的名字\t容器的IP\t容器的端口")
for i in range(len(containers)):
print("\t\t%4s\t\t%s\t\t%s\t%s\t%s" %(containers[i][0],containers[i][1],str.center(containers[i][2],10),containers[i][3],str.center(containers[i][4],8)))
def unalive_instances():
"""当前没有运行的实例的ID"""
unalive_instance = shell(unalive_docker_id).split('\n')
return unalive_instance, len(unalive_instance)
def get_unalive_instances_infos():
container_id, _ = unalive_instances()
containers_name = shell(unalive_docker_name).split('\n')
containers_ip, containers, ins_code = [], [], []
for i in container_id:
containers_ip.append("未运行,无IP")
for k in range(len(containers_ip)):
containers.append([str(k + 1), container_id[k], containers_name[k], containers_ip[k]])
ins_code.append(k + 1)
return containers, ins_code
def show_unalive_instance():
containers, _ = get_unalive_instances_infos()
print("\tNow,the instances not running are list as follows: ")
print("\t\t实例编号\t容器的ID\t\t容器的名字\t\t容器的IP")
for container in containers:
print('\t', end="")
for info in container:
print("\t%4s" % info, end="\t ")
print()
print()
def start_instance(value):
containers = value
for container in containers:
try:
shell(start_ins + container[1])
print("start %s successful" % container[1])
except BaseException as e:
print("开启实例的时候好像出了点问题...")
def stop_instance(value):
containers = value
for container in containers:
try:
shell(stop_ins + container[1])
print("stop %s successful" % container[1])
except BaseException as e:
print("关闭实例的时候好像出了点问题...")
def docker_menu():
print(">>" * 5, "Docker managemet program by valecalida", "<<" * 5)
print("\t\t1 >> 查看当前docker的运行状态")
print("\t\t2 >> 开启指定(全部)容器")
print("\t\t3 >> 关闭指定(全部)容器")
print("\t\tq >> 退出程序(q)")
def main():
while True:
docker_menu()
len_alive = len(shell(alive_docker_id).split())
total = len(shell(total_docker_id).split('\n'))
len_unalive = total - len_alive
user_choice_1 = input("输入您想要进行的操作的序号 >> ")
if user_choice_1 == 'q':
print('\t程序将在一秒后自动退出')
time.sleep(1)
sys.exit()
elif user_choice_1 == '1':
if len_alive == 0 and len_unalive != 0:
show_unalive_instance()
elif len_unalive == 0 and len_alive != 0:
show_alive_instance()
elif len_alive != 0 and len_unalive != 0:
show_unalive_instance()
show_alive_instance()
elif user_choice_1 == '2':
if len_unalive == 0:
print("\t当前没有未开启的docker容器\n")
else:
show_unalive_instance()
containers, ins_code = get_unalive_instances_infos()
user_choice_2 = input("请输入您想要启动的docker实例编号(a all) >> ")
try:
if user_choice_2 == 'a':
start_instance(containers)
elif user_choice_2 == 'q':
print("\t正在返回上级菜单...")
elif int(user_choice_2) in ins_code:
for i in range(len(ins_code) + 1):
if int(user_choice_2) == i + 1:
start_instance([containers[i]])
break
else:
continue
else:
print("\t看起来您的输入好像有点问题...")
except BaseException as e:
print("\t看起来您的输入好像有点问题...")
elif user_choice_1 == '3':
flag = len(shell(alive_docker_id).split())
if flag == 0:
print("当前没有在运行的实例,无需执行关闭操作")
else:
show_alive_instance()
containers, ins_code = get_alive_instances_infos()
user_choice_2 = input("请输入您想要关闭的docker实例编号(a all) >> ")
try:
if user_choice_2 == 'a':
stop_instance(containers)
elif user_choice_2 == 'q':
print("\t正在返回上级菜单...")
elif int(user_choice_2) in ins_code:
for i in range(len(ins_code) + 1):
if int(user_choice_2) == i + 1:
stop_instance([containers[i]])
break
else:
continue
else:
print("\t看起来您的输入好像有点问题...")
except BaseException as e:
print("\t看起来您的输入好像有点问题...")
else:
print("\t您的输入好像不太符合要求")
if __name__ == '__main__':
main()
三、执行效果
1、查看当前docker的运行状态
>>>>>>>>>> Docker managemet program by valecalida <<<<<<<<<<
1 >> 查看当前docker的运行状态
2 >> 开启指定(全部)容器
3 >> 关闭指定(全部)容器
q >> 退出程序(q)
输入您想要进行的操作的序号 >> 1
Now,the instances not running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP
1 7ffb7ab9357b ctfd_ctfd_1 未运行,无IP
2 5647bf40afb6 ctfd_cache_1 未运行,无IP
3 9850433d5ea5 ctfd_db_1 未运行,无IP
Now,the instances running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP 容器的端口
1 80a350cee15c wordpress 172.18.0.3 80
2 26d6109587e8 mysql 172.18.0.2 3306
2、开启指定容器
输入您想要进行的操作的序号 >> 2
Now,the instances not running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP
1 7ffb7ab9357b ctfd_ctfd_1 未运行,无IP
2 5647bf40afb6 ctfd_cache_1 未运行,无IP
3 9850433d5ea5 ctfd_db_1 未运行,无IP
请输入您想要启动的docker实例编号(a all) >> 1
start 7ffb7ab9357b successful
>>>>>>>>>> Docker managemet program by valecalida <<<<<<<<<<
1 >> 查看当前docker的运行状态
2 >> 开启指定(全部)容器
3 >> 关闭指定(全部)容器
q >> 退出程序(q)
输入您想要进行的操作的序号 >> 1
Now,the instances not running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP
1 5647bf40afb6 ctfd_cache_1 未运行,无IP
2 9850433d5ea5 ctfd_db_1 未运行,无IP
Now,the instances running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP 容器的端口
1 80a350cee15c wordpress 172.18.0.3 80
2 26d6109587e8 mysql 172.18.0.2 3306
3 7ffb7ab9357b ctfd_ctfd_1 172.20.0.2 8000
3、关闭指定容器
输入您想要进行的操作的序号 >> 3
Now,the instances running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP 容器的端口
1 80a350cee15c wordpress 172.18.0.3 80
2 26d6109587e8 mysql 172.18.0.2 3306
3 7ffb7ab9357b ctfd_ctfd_1 172.20.0.2 8000
请输入您想要关闭的docker实例编号(a all) >> 3
stop 7ffb7ab9357b successful
>>>>>>>>>> Docker managemet program by valecalida <<<<<<<<<<
1 >> 查看当前docker的运行状态
2 >> 开启指定(全部)容器
3 >> 关闭指定(全部)容器
q >> 退出程序(q)
输入您想要进行的操作的序号 >> 1
Now,the instances not running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP
1 7ffb7ab9357b ctfd_ctfd_1 未运行,无IP
2 5647bf40afb6 ctfd_cache_1 未运行,无IP
3 9850433d5ea5 ctfd_db_1 未运行,无IP
Now,the instances running are list as follows:
实例编号 容器的ID 容器的名字 容器的IP 容器的端口
1 80a350cee15c wordpress 172.18.0.3 80
2 26d6109587e8 mysql 172.18.0.2 3306
4、退出程序
输入您想要进行的操作的序号 >> q
程序将在一秒后自动退出