基于 docker inspect + Python3 反向生成容器启动命令

export-docker-startup-command.py

程序支持将选择单个容器,将容器的启动命令打印到 console,或导出所有容器的启动命令到以时间戳命名的 txt 文件中

#!/usr/bin/python3

import argparse
import datetime
import json
import math
import os
import sys

containerIds=[]
containerNames=[]
containerImages=[]
selectContainerIndex=None

programTitle = "================= 本程序负责批量或选定Docker容器导出其启动命令 Powered by 王睿 ================="

def welcome():
  supportArgs = ["-d", "-P", "-p", "-v", "-e", "--name", "--restart", "--entrypoint", "--privileged", "--memory"]
  print("\n" + programTitle)
  print("支持导出的启动参数如下:")
  #for arg in supportArgs:
  print(supportArgs)
  print("================================================================================================")

def exec(command):
  return os.popen(command).read().strip()

# 获取容器列表数据
def getContainerListData():

  global containerIds
  global containerNames
  global containerImages
  
  # 容器id集合
  containerIds = exec("docker ps -a --format '{{.ID}}'").split("\n")
  # 容器名称集合
  containerNames = exec("docker ps -a --format '{{.Names}}'").split("\n")
  # 容器镜像集合
  containerImages = exec("docker ps -a --format '{{.Image}}'").split("\n")

  colume1 = "INDEX"
  colume2 = "CONTAINER ID"
  colume3 = "NAMES"
  colume4 = "IMAGE"

  # 每列之间间隔的字符串,默认是三个空格
  columeIntervalString = "   "
  maxNameLen = 0
  for i in range(len(containerNames)):
    if (maxNameLen < len(containerNames[i])):
      maxNameLen = len(containerNames[i])

  tableTitle1 = colume1 + columeIntervalString + colume2 + columeIntervalString + colume3
  for i in range(maxNameLen):
    if (i >= len(colume3)):
      tableTitle1 += " "
  tableTitle1 += columeIntervalString
  tableTitle = tableTitle1 + colume4
  print(tableTitle)
  
  for i in range(len(containerIds)):
    item = str(i+1)
    for j in range(len(tableTitle1)):
      if (j > len(item) and j <= len(colume1) + len(columeIntervalString)):
        item += " "
    
    item += containerIds[i]
    for j in range(len(tableTitle1)):
      if (j > len(item) and j <= len(colume1) + len(colume2) + len(columeIntervalString)*2):
        item += " "
    
    item += containerNames[i]
    for j in range(len(tableTitle1) + 1):
      if (j > len(item) and j <= len(tableTitle1)):
        item += " "
        
    item += containerImages[i]
    print(item)
    
# 选择容器序号
def selectContainer():

  global containerIds
  global containerNames
  global containerImages
  global selectContainerIndex
  
  print("\n请输入导出的容器序号、容器ID或容器名称:", end = "")
  try:
    inputText = input()
  except KeyboardInterrupt:
    print("\n\n操作取消,程序退出\n")
    exit(0)
    
  selectContainerIndex = getContainerIndex(inputText)
  if selectContainerIndex == None:
    print("未选中任何任何容器,请重新选择")
    selectContainer()
  else:
    print("\n当前选中的容器名称为:" + containerNames[selectContainerIndex])
    

# 根据用户的输入获取容器索引
def getContainerIndex(text):
  try:
    intVal = int(text) - 1
    if intVal >= 0 and intVal < len(containerIds):
      return intVal
  except:
    print()
  
  for i in range(len(containerIds)):
    if containerIds[i] == text:
      return i
  for i in range(len(containerNames)):
    if containerNames[i] == text:
      return i
  for i in range(len(containerIds)):
    if containerIds[i].startswith(text):
      return i
  for i in range(len(containerNames)):
    if containerNames[i].startswith(text):
      return i
      
  return None
  
# 组织容器参数
def getCommandByContainerIndex(containerIndex):
  
  command = "docker run -d"

  imageInspect = json.loads(exec("docker image inspect {}".format(containerImages[containerIndex])))
  containerInspect = json.loads(exec("docker container inspect {}".format(containerIds[containerIndex])))
  imageConfig = imageInspect[0]['Config']
  containerConfig = containerInspect[0]['Config']
  containerHostConfig = containerInspect[0]['HostConfig']
  
  if (containerHostConfig['PublishAllPorts'] == True):
    command += "P"
    
  command += " \\\n --name " + containerInspect[0]['Name'][1:]
  command += " \\\n --restart " + containerHostConfig['RestartPolicy']['Name']
  
  imageEntrypoints = imageConfig['Entrypoint'] 
  containerEntrypoints = containerConfig['Entrypoint']
  if(containerEntrypoints != None and containerEntrypoints != imageEntrypoints):
    command += " \\\n --entrypoint " + containerEntrypoints[0]
  
  if (containerHostConfig['Privileged'] == True):
    command += " \\\n --privileged "
  
  containerBinds = containerHostConfig['Binds']  
  if (containerBinds != None):
    for bind in containerBinds:
      command += " \\\n -v " + bind

  imageEnvs = imageConfig['Env']
  containerEnvs = containerConfig['Env']   
  for containerEnv in containerEnvs:
    if(containerEnv not in imageEnvs):
      command += " \\\n -e \"" + containerEnv + "\""
      
  containerPortBindings = containerHostConfig['PortBindings']     
  for containerPort in containerPortBindings:
    hostPortArr = containerPortBindings[containerPort]
    for hostPortObj in hostPortArr:
      command += " \\\n -p " + hostPortObj['HostPort'] + ":" + containerPort

  memory = containerHostConfig['Memory']
  if memory > 0:
    memoryStr = str(memory)
    kbBytes = 1024
    mbBytes = kbBytes * 1024
    gbBytes = mbBytes * 1024
    if memory >= gbBytes and memory % gbBytes == 0:
      memoryStr = str(round(memory / gbBytes)) + "g"
    elif memory >= mbBytes and memory % mbBytes == 0:
      memoryStr = str(round(memory / mbBytes)) + "m"
    elif memory >= kbBytes and memory % kbBytes == 0:
      memoryStr = str(round(memory / kbBytes)) + "k"
    command += " \\\n --memory " + memoryStr
    
  command += " \\\n " + containerImages[containerIndex]
  
  imageCmd = imageConfig['Cmd']
  containerCmd = containerConfig['Cmd']
  if(containerCmd != None and containerCmd != imageCmd):
    for cmd in containerCmd:
      command += " \\\n " + cmd
       
  return command



def parse_args():
  parser = argparse.ArgumentParser(description = programTitle)
  parser.add_argument('--export-all', type=bool, default = False, help = "是否将所有容器的启动命令导出到文件,默认值: false")
  args = parser.parse_args()
  return args

if __name__ == '__main__':
  args = parse_args()
  localDir = os.path.split(os.path.realpath(__file__))[0]
  welcome()
  getContainerListData()
  command = ""
  if args.export_all:
    fileName = localDir + "/" + "docker-startup-all-" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + ".txt"
    for i in range(len(containerIds)):
      command += getCommandByContainerIndex(i) + "\n\n\n"
    with open(fileName, "w") as f:
      f.write(command)
    print("\n所有容器的启动命令已导出到文件:" + fileName + "\n")
  else:
    selectContainer()
    command = getCommandByContainerIndex(selectContainerIndex)
    print("\n" + command + "\n")

 

--help 帮助

 

导出单个容器启动命令

 

一次导出所有容器启动命令

posted @ 2022-06-28 17:14  Nihaorz  阅读(336)  评论(0)    收藏  举报