Docker容器获取宿主机信息
最近在做产品授权的东西,开始宿主机为Window,程序获取机器硬件信息相对简单些,后来部署时发现各种各样的的环境问题,所有后来改用dokcer部署,docker方式获取宿主机信息时花了些时间,特此记录一下
docker 获取宿主机的信息
// dmidecode -t 4 | grep ID | tail -1 // CPUID // 系统 // dmidecode -s system-serial-number // 查看系统序列号 // dmidecode -s system-uuid // 查看系统UUID // dmidecode -s system-product-name //查看服务器系统型号 // dmidecode -s processor-manufacturer | tail -1 // 处理器厂家 // 主板 // dmidecode -s baseboard-product-name // 主板型号 // dmidecode -s baseboard-serial-number // 主板序列号 // dmidecode -s baseboard-manufacturer // 主板厂家
实际项目当中,我获取了CPUID、系统序列号、系统UUID、系统型号、处理器厂家,之所有获取这么多信息标识机器,是考虑到有些信息在某些系统可能为空,而且CPUID也不唯一了,所以就多获取些。
调查下来,docker 获取宿主机信息大体可以通过三种方式
- 通过环境变量由外部传入容器内
-
使用挂载宿主机目录方式
- 在容器中使用ssh连接到主机
一:通过环境变量由外部传入容器内
大体思路是docker 支持通过-e来传递参数到容器内部程序,就像安装docker-mysql那样密码可以通过参数传递一样
- 在DockeFile中增加环境变量配置节点 (此步骤主要用来设置参数默认,也可以省略,通过其它方式设置)
- 在程序启动时应用获取程序变量并应用
- 在docker run 时通过-e参数传递到容器中
二:使用挂载宿主机目录方式
确保宿主机能执行dmidecode命令(必须)
将宿主机的如下两个目录挂载到容器中
// dmidecode程序的目录,如果不挂载那么容器中识别不了dmidecode命令 /usr/sbin/dmidecode或者/sbin/dmidecode // dmidecode调用时会使用到mem这个文件,如果不挂载会找不到文件 /dev/mem
在容器启动时增加 --privileged = true参数,让容器获得近似于宿主机root的权限
三:在容器中使用ssh连接到主机
思路:在docker容器内安装ssh,sshpass服务,通过ssh连接到宿主机执行命令,获 取宿主机信息(必须知道宿主机Ip和密码)
步骤:
- 安装服务 yum -y install openssh-server
- 修改配置 vim /etc/ssh/sshd_config PermitRootLogin的值修改为yes保存退出
- 启动ssh服务 systemctl start sshd.service
- 设置开机启动 systemctl enable sshd.service
- 安装sshpass yum -y install sshpass
Window 获取设备信息帮助类
1 /// <summary> 2 /// 注册帮助类 3 /// </summary> 4 public class RegisterHelper 5 { 6 // 机器指纹字符串 7 private static string m_FingerPrintString = string.Empty; 8 9 /// <summary> 10 /// Get a string Unique Identification code of a computer 11 /// </summary> 12 /// <returns></returns> 13 public static string StringValue(string mac) 14 { 15 if (string.IsNullOrEmpty(m_FingerPrintString)) 16 { 17 m_FingerPrintString = "MAC >> " + mac + "\nCPU >> " + GetCpuId() + "\nBIOS >> " + GetBiosId() + "\nBASE >> " + GetBaseId() 18 + "\nDISK >> " + GetDiskId() + "\nVIDEO >> " + GetVideoId(); 19 } 20 return m_FingerPrintString; 21 } 22 23 /// <summary> 24 /// First enabled network card ID 25 /// </summary> 26 /// <returns></returns> 27 public static string GetMacId() 28 { 29 return Identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled"); 30 } 31 32 /// <summary> 33 /// Get the cpuID 34 /// </summary> 35 /// <returns></returns> 36 private static string GetCpuId() 37 { 38 //Uses first CPU identifier available in order of preference 39 //Don't get all identifiers, as it is very time consuming 40 string retVal = Identifier("Win32_Processor", "UniqueId"); 41 if (string.IsNullOrEmpty(retVal)) //If no UniqueID, use ProcessorID 42 { 43 retVal = Identifier("Win32_Processor", "ProcessorId"); 44 if (string.IsNullOrEmpty(retVal)) //If no ProcessorId, use Name 45 { 46 retVal = Identifier("Win32_Processor", "Name"); 47 if (string.IsNullOrEmpty(retVal)) //If no Name, use Manufacturer 48 { 49 retVal = Identifier("Win32_Processor", "Manufacturer"); 50 } 51 //Add clock speed for extra security 52 retVal += Identifier("Win32_Processor", "MaxClockSpeed"); 53 } 54 } 55 return retVal; 56 } 57 58 /// <summary> 59 /// BIOS Identifier 60 /// </summary> 61 /// <returns></returns> 62 private static string GetBiosId() 63 { 64 return Identifier("Win32_BIOS", "Manufacturer") + " | " + Identifier("Win32_BIOS", "SMBIOSBIOSVersion") 65 + " | " + Identifier("Win32_BIOS", "IdentificationCode") + " | " + Identifier("Win32_BIOS", "SerialNumber") 66 + " | " + Identifier("Win32_BIOS", "ReleaseDate") + " | " + Identifier("Win32_BIOS", "Version") 67 + " | " + Identifier("Win32_BIOS", "Name"); 68 } 69 70 /// <summary> 71 /// Main physical hard drive ID 72 /// </summary> 73 /// <returns></returns> 74 private static string GetDiskId() 75 { 76 return Identifier("Win32_DiskDrive", "Model") + " | " + Identifier("Win32_DiskDrive", "SerialNumber") 77 + " | " + Identifier("Win32_DiskDrive", "Signature") + " | " + Identifier("Win32_DiskDrive", "TotalHeads"); 78 } 79 80 /// <summary> 81 /// Motherboard ID 82 /// </summary> 83 /// <returns></returns> 84 private static string GetBaseId() 85 { 86 return Identifier("Win32_BaseBoard", "Model") + " | " + Identifier("Win32_BaseBoard", "Manufacturer") 87 + " | " + Identifier("Win32_BaseBoard", "Name") + " | " + Identifier("Win32_BaseBoard", "SerialNumber") 88 + " | " + Identifier("Win32_BaseBoard", "SKU") + " | " + Identifier("Win32_BaseBoard", "Product"); 89 } 90 91 /// <summary> 92 /// Primary video controller ID 93 /// </summary> 94 /// <returns></returns> 95 private static string GetVideoId() 96 { 97 return Identifier("Win32_VideoController", "Name") + " | " + Identifier("Win32_VideoController", "AdapterRAM"); 98 } 99 100 /// <summary> 101 /// Return a hardware identifier 102 /// </summary> 103 /// <param name="wmiClass"></param> 104 /// <param name="wmiProperty"></param> 105 /// <returns></returns> 106 private static string Identifier(string wmiClass, string wmiProperty) 107 { 108 string result = string.Empty; 109 System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass); 110 System.Management.ManagementObjectCollection moc = mc.GetInstances(); 111 foreach (System.Management.ManagementObject mo in moc) 112 { 113 //Only get the first one 114 if (string.IsNullOrEmpty(result)) 115 { 116 try 117 { 118 result = mo[wmiProperty]?.ToString(); 119 break; 120 } 121 catch(Exception e) 122 { 123 LogSingleton.CreateInstance().Error(e, "Window获取硬件信息失败"); 124 } 125 } 126 } 127 return result; 128 } 129 130 /// <summary> 131 /// Return a hardware identifier 132 /// </summary> 133 /// <param name="wmiClass"></param> 134 /// <param name="wmiProperty"></param> 135 /// <param name="wmiMustBeTrue"></param> 136 /// <returns></returns> 137 private static string Identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue) 138 { 139 string result = string.Empty; 140 System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass); 141 System.Management.ManagementObjectCollection moc = mc.GetInstances(); 142 foreach (System.Management.ManagementObject mo in moc) 143 { 144 if (mo[wmiMustBeTrue].ToString() == "True") 145 { 146 //Only get the first one 147 if (string.IsNullOrEmpty(result)) 148 { 149 try 150 { 151 result = mo[wmiProperty]?.ToString(); 152 break; 153 } 154 catch(Exception e) 155 { 156 LogSingleton.CreateInstance().Error(e,"Window获取硬件信息失败"); 157 } 158 } 159 } 160 } 161 return result; 162 } 163 }
Linux 获取设备信息帮助类
1 public class LinuxHelper 2 { 3 4 // sudo dmidecode -t 4 | grep ID | tail -1 // CPUID 5 6 // 系统 7 // sudo dmidecode -s system-serial-number // 查看系统序列号 8 // sudo dmidecode -s system-uuid // 查看系统UUID 9 // sudo dmidecode -s system-product-name // 查看服务器系统型号 10 // sudo dmidecode -s processor-manufacturer | tail -1 // 处理器厂家 11 12 // 主板 13 // sudo dmidecode -s baseboard-product-name // 主板型号 14 // sudo dmidecode -s baseboard-serial-number // 主板序列号 15 // sudo dmidecode -s baseboard-manufacturer // 主板厂家 16 17 /// <summary> 18 /// Get a string Unique Identification code of a computer 19 /// </summary> 20 /// <returns></returns> 21 public static string StringValue() 22 { 23 string cpuID = GetCpuId(); 24 string serialNumber = GetSerialNumber(); 25 string productName = GetProductName(); 26 string processorManufacturer = GetProcessorManufacturer(); 27 if (string.IsNullOrWhiteSpace(cpuID) && string.IsNullOrWhiteSpace(serialNumber) && string.IsNullOrWhiteSpace(productName) && string.IsNullOrWhiteSpace(processorManufacturer)) 28 { 29 return string.Empty; 30 } 31 return "CPU >> " + cpuID + "\nSerialNumber >> " + serialNumber + "\nProductName >> " + productName + "\nProcessorManufacturer >> " + processorManufacturer; 32 } 33 34 35 /// <summary> 36 /// Get the cpuID 37 /// </summary> 38 /// <returns></returns> 39 private static string GetCpuId() 40 { 41 return ProcessShell("dmidecode -t 4 | grep ID | tail -1"); 42 } 43 44 /// <summary> 45 /// SerialNumber 46 /// </summary> 47 /// <returns></returns> 48 private static string GetSerialNumber() 49 { 50 return ProcessShell("dmidecode -s system-serial-number"); 51 } 52 53 /// <summary> 54 /// product-name 55 /// </summary> 56 /// <returns></returns> 57 private static string GetProductName() 58 { 59 return ProcessShell("dmidecode -s system-product-name"); 60 } 61 62 /// <summary> 63 /// ProcessorManufacturer 64 /// </summary> 65 /// <returns></returns> 66 private static string GetProcessorManufacturer() 67 { 68 return ProcessShell("dmidecode -s processor-manufacturer | tail -1"); 69 } 70 71 /// <summary> 72 /// 执行Shell命令 73 /// </summary> 74 /// <param name="shellCmd"></param> 75 /// <returns></returns> 76 private static string ProcessShell(string shellCmd) 77 { 78 string result = string.Empty; 79 try 80 { 81 using Process process = new Process 82 { 83 StartInfo = new ProcessStartInfo("/bin/bash", "") 84 }; 85 process.StartInfo.RedirectStandardInput = true; 86 process.StartInfo.RedirectStandardOutput = true; 87 process.StartInfo.UseShellExecute = false; 88 process.Start(); 89 process.StandardInput.WriteLine(shellCmd); 90 process.StandardInput.Close(); 91 result = process.StandardOutput.ReadToEnd(); 92 process.WaitForExit(); 93 } 94 catch (Exception e) 95 { 96 LogSingleton.CreateInstance().Error(e, "Linux获取硬件信息失败"); 97 } 98 return result; 99 }
补充:方案二在实际测试中,发布在Ubuntu 22.04 TSL版本中获取宿主机信息失败。大致错误为找不到相关文件。
最终采取的方式为在容器中获取授权服务容器的ID,以此作为唯一标识(具体采用哪种方式看自己的实际应用环境)
关键代码
1 /// <summary> 2 /// 获取所有容器信息 3 /// </summary> 4 /// <returns></returns> 5 private static List<ContainerListResponse> GetContainerList() 6 { 7 string apiVersion = Environment.GetEnvironmentVariable("DockerApiVersin", EnvironmentVariableTarget.Process); 8 apiVersion = string.IsNullOrWhiteSpace(apiVersion) ? "1.37" : apiVersion; 9 string result = ProcessShell($"curl --unix-socket /var/run/docker.sock http://172.17.0.1/v{apiVersion}/containers/json"); 10 return JsonConvert.DeserializeObject<List<ContainerListResponse>>(result); 11 }
1 IList<ContainerListResponse> containers = GetContainerList(); 2 ContainerListResponse containerListResponse = containers.FirstOrDefault(c => c.Names.Any(n => n.Contains("tuguan-server-license"))); 3 return containerListResponse?.ID;
// 目录挂载 -v /var/run/docker.sock:/var/run/docker.sock
参考信息 :https://blog.csdn.net/qq_42910468/article/details/121387411
https://blog.csdn.net/weixin_42173451/article/details/123085460