解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
4.78 KiB
X
namespace NewLife;

/// <summary>机器信息容器检测部分</summary>
public partial class MachineInfo
{
    #region 容器检测
    /// <summary>是否运行在容器中</summary>
    /// <remarks>
    /// 检测依据:
    /// 1. 环境变量 DOTNET_RUNNING_IN_CONTAINER
    /// 2. 存在 /.dockerenv 文件
    /// 3. /proc/1/cgroup 包含 docker/kubepods/containerd 等关键字
    /// </remarks>
    public static Boolean IsInContainer
    {
        get
        {
            // 环境变量检测
            var env = Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER");
            if (env.EqualIgnoreCase("true", "1")) return true;

            if (!Runtime.Linux) return false;

            // Docker 环境文件检测
            if (File.Exists("/.dockerenv")) return true;

            // cgroup 检测
            var cgroupFile = "/proc/1/cgroup";
            if (File.Exists(cgroupFile))
            {
                try
                {
                    var content = File.ReadAllText(cgroupFile);
                    if (content.Contains("docker") ||
                        content.Contains("kubepods") ||
                        content.Contains("containerd") ||
                        content.Contains("lxc"))
                        return true;
                }
                catch { }
            }

            return false;
        }
    }

    /// <summary>获取容器资源限制</summary>
    /// <returns>元组:(内存限制字节数, CPU核数限制)。返回null表示无限制或获取失败</returns>
    /// <remarks>
    /// 读取 cgroup v1/v2 的资源限制配置:
    /// - 内存限制:/sys/fs/cgroup/memory/memory.limit_in_bytes (v1) 或 /sys/fs/cgroup/memory.max (v2)
    /// - CPU限制:/sys/fs/cgroup/cpu/cpu.cfs_quota_us 和 cpu.cfs_period_us (v1) 或 /sys/fs/cgroup/cpu.max (v2)
    /// </remarks>
    public static (Int64? MemoryLimit, Double? CpuLimit) GetContainerLimits()
    {
        Int64? memoryLimit = null;
        Double? cpuLimit = null;

        if (!Runtime.Linux) return (memoryLimit, cpuLimit);

        // 尝试读取内存限制
        // cgroup v2
        var memFile = "/sys/fs/cgroup/memory.max";
        if (File.Exists(memFile))
        {
            if (TryRead(memFile, out var value) && value != "max")
                memoryLimit = value.ToLong();
        }
        else
        {
            // cgroup v1
            memFile = "/sys/fs/cgroup/memory/memory.limit_in_bytes";
            if (File.Exists(memFile) && TryRead(memFile, out var value))
            {
                var limit = value.ToLong();
                // 如果接近系统最大值(通常是一个很大的数),则认为无限制
                if (limit > 0 && limit < 9_000_000_000_000_000_000L)
                    memoryLimit = limit;
            }
        }

        // 尝试读取 CPU 限制
        // cgroup v2: cpu.max 格式为 "quota period" 或 "max period"
        var cpuFile = "/sys/fs/cgroup/cpu.max";
        if (File.Exists(cpuFile))
        {
            if (TryRead(cpuFile, out var value))
            {
                var parts = value.Split(' ');
                if (parts.Length >= 2 && parts[0] != "max")
                {
                    var quota = parts[0].ToLong();
                    var period = parts[1].ToLong();
                    if (quota > 0 && period > 0)
                        cpuLimit = (Double)quota / period;
                }
            }
        }
        else
        {
            // cgroup v1
            var quotaFile = "/sys/fs/cgroup/cpu/cpu.cfs_quota_us";
            var periodFile = "/sys/fs/cgroup/cpu/cpu.cfs_period_us";
            if (File.Exists(quotaFile) && File.Exists(periodFile))
            {
                if (TryRead(quotaFile, out var quotaStr) && TryRead(periodFile, out var periodStr))
                {
                    var quota = quotaStr.ToLong();
                    var period = periodStr.ToLong();
                    // quota=-1 表示无限制
                    if (quota > 0 && period > 0)
                        cpuLimit = (Double)quota / period;
                }
            }
        }

        return (memoryLimit, cpuLimit);
    }

    /// <summary>获取容器内存使用量</summary>
    /// <returns>当前内存使用量(字节)。获取失败返回null</returns>
    public static Int64? GetContainerMemoryUsage()
    {
        if (!Runtime.Linux) return null;

        // cgroup v2
        var usageFile = "/sys/fs/cgroup/memory.current";
        if (File.Exists(usageFile) && TryRead(usageFile, out var value))
            return value.ToLong();

        // cgroup v1
        usageFile = "/sys/fs/cgroup/memory/memory.usage_in_bytes";
        if (File.Exists(usageFile) && TryRead(usageFile, out value))
            return value.ToLong();

        return null;
    }
    #endregion
}