この記事では、Linux 名前空間に関する関連知識を提供します。名前空間は軽量な形式の仮想化を提供し、実行中のシステムのグローバル プロパティをさまざまな側面から表示できるようにします。皆様のお役に立てれば幸いです。
ネームスペース (Linux ネームスペース) は、コンテナー仮想化のために実装された Linux カーネルの機能です。作成した各コンテナーには独自の名前空間があり、コンテナー内で実行されるアプリケーションは、あたかも独立したオペレーティング システムで実行されているかのようになり、コンテナーが相互に影響を及ぼさないように名前空間が確保されます。
Linux の名前空間メカニズムは、リソース分離のソリューションを提供します。 PID、IPC、ネットワークなどのシステム リソースはグローバルではなくなり、特定の名前空間に属します。ネームスペースは、グローバル システム リソースの一種のカプセル化と分離であり、異なるネームスペース内のプロセスが独立したグローバル システム リソースを持つようになります。ネームスペース内のシステム リソースを変更すると、現在のネームスペース内のプロセスにのみ影響し、他のネームスペース内のプロセスには影響しません。
従来、Linux および UNIX のその他の派生バージョンでは、多くのリソースがグローバルに管理されていました。たとえば、システム内のすべてのプロセスは従来、PID によって識別されます。これは、カーネルが PID のグローバル リストを管理する必要があることを意味します。さらに、uname システム コールを通じてすべての呼び出し元から返されるシステム関連情報 (システム名やカーネルに関する一部の情報を含む) は同じです。ユーザー ID も同様の方法で管理されます。つまり、各ユーザーはグローバルに一意の UID 番号によって識別されます。
グローバル ID を使用すると、カーネルは特定の権限を選択的に許可または拒否できます。 UID 0 の root ユーザーは基本的にすべての操作を許可されますが、他のユーザー ID は制限されます。たとえば、UID n のユーザーは、ユーザー m (m≠ n) に属するプロセスを強制終了することはできません。ただし、これによってユーザーがお互いに会うことが妨げられるわけではありません。つまり、ユーザー n は、別のユーザー m もコンピューター上でアクティブであることがわかります。ユーザーが自分のプロセスのみを操作できる限り、これは問題ありません。ユーザーが他のユーザーのプロセスを表示できない理由はないからです。
ただし、この影響が望ましくない状況も考えられます。 Web ホスティングのプロバイダーが、root 権限を含む Linux コンピューターへのフル アクセスをユーザーに提供することを意図している場合。従来、これには各ユーザーにコンピュータが必要で、法外に高価でした。この問題を解決するには、KVM や VMWare が提供する仮想化環境を使用することが考えられますが、リソースの割り当てがあまり良くありません。コンピューターの各ユーザーには、個別のカーネルと、サポートするユーザーレベルのアプリケーションの完全にインストールされたセットが必要です。
名前空間は、必要なリソースが少ない別のソリューションを提供します。仮想化システムでは、物理コンピューターは複数のコア、場合によっては複数の異なるオペレーティング システムを並行して実行できます。名前空間は、1 台の物理コンピューター上で動作するために 1 つのカーネルのみを使用し、前述のすべてのグローバル リソースは名前空間を通じて抽象化されます。これにより、一連のプロセスを互いに分離されたコンテナーに配置することが可能になります。分離により、コンテナーのメンバーは他のコンテナーと関係を持たなくなります。ただし、コンテナー間で一定量の情報を共有できるようにすることで、コンテナー間の分離を減らすこともできます。たとえば、コンテナーは、独自の PID セットを使用しながらも、ファイル システムの一部を他のコンテナーと共有するように設定できます。
名前空間の実装には、各サブシステムの名前空間構造、以前のすべてのグローバルコンポーネントを名前空間にパッケージ化すること、および特定のプロセスを各名前空間のメカニズムに関連付けるという 2 つの部分が必要です。それが属するもの。
サブシステムの以前はグローバルなプロパティは名前空間にカプセル化され、各プロセスは選択された名前空間に関連付けられます。すべての名前空間対応カーネル サブシステムは、名前空間として提供されるすべてのオブジェクトを収集するデータ構造を提供する必要があります。 struct nsproxy は、サブシステム固有の名前空間ラッパーへのポインターをアセンブルするために使用されます。ファイル nsproxy.h には、以下があります。
/* * A structure to contain pointers to all per-process * namespaces - fs (mount), uts, network, sysvipc, etc. * * The pid namespace is an exception -- it's accessed using * task_active_pid_ns. The pid namespace here is the * namespace that children will use. * * 'count' is the number of tasks holding a reference. * The count for each namespace, then, will be the number * of nsproxies pointing to it, not the number of tasks. * * The nsproxy is shared by tasks which share all namespaces. * As soon as a single namespace is cloned or unshared, the * nsproxy is copied. */struct nsproxy { atomic_t count; struct uts_namespace *uts_ns; struct ipc_namespace *ipc_ns; struct mnt_namespace *mnt_ns; struct pid_namespace *pid_ns_for_children; struct net *net_ns; struct time_namespace *time_ns; struct time_namespace *time_ns_for_children; struct cgroup_namespace *cgroup_ns;};
現在のカーネルの次のスコープは、名前空間
1. UTS 名前空間には、名前、バージョン、基礎となるアーキテクチャ タイプなどが含まれます。実行中のカーネルの情報。 UTS は UNIX Timesharing System の略称です。
2. プロセス間通信 (IPC) に関連するすべての情報は、struct ipc_namespace に格納されます。
3. マウントされたファイル システムのビューは、struct mnt_namespace に示されます。
4. プロセス ID に関する情報は、struct pid_namespace によって提供されます。
5. struct user_namespace によって保存された情報は、各ユーザーのリソース使用量を制限するために使用されます。
6. struct net_ns には、ネットワーク関連の名前空間パラメータがすべて含まれています。
対応するサブシステムを説明する際に、各名前空間コンテナの内容を紹介します。新しいプロセスを作成するときにフォークを使用して新しい名前空間を確立できるため、この動作を制御するには適切なフラグを指定する必要があります。各名前空間には対応するフラグがあり、sched.h ファイル内にあります:
#define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ #define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ #define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ #define CLONE_NEWUSER 0x10000000 /* New user namespace */ #define CLONE_NEWPID 0x20000000 /* New pid namespace */ #define CLONE_NEWNET 0x40000000 /* New network namespace */
さまざまなタイプの名前空間の機能:
IPC:用于隔离进程间通讯所需的资源( System V IPC, POSIX message queues),PID命名空间和IPC命名空间可以组合起来用,同一个IPC名字空间内的进程可以彼此看见,允许进行交互,不同空间进程无法交互
Network:Network Namespace为进程提供了一个完全独立的网络协议栈的视图。包括网络设备接口,IPv4和IPv6协议栈,IP路由表,防火墙规则,sockets等等。一个Network Namespace提供了一份独立的网络环境,就跟一个独立的系统一样。
Mount:每个进程都存在于一个mount Namespace里面, mount Namespace为进程提供了一个文件层次视图。如果不设定这个flag,子进程和父进程将共享一个mount Namespace,其后子进程调用mount或umount将会影响到所有该Namespace内的进程。如果子进程在一个独立的mount Namespace里面,就可以调用mount或umount建立一份新的文件层次视图。
PID::linux通过命名空间管理进程号,同一个进程,在不同的命名空间进程号不同!进程命名空间是一个父子结构,子空间对于父空间可见。
User:用于隔离用户
UTS:用于隔离主机名
每个进程都关联到自身的命名空间视图,在任务定义的结构体task_struct中有如下定义:
struct task_struct {.../* 命名空间 */struct nsproxy *nsproxy;...}
因为使用了指针,多个进程可以共享一组子命名空间。这样,修改给定的命名空间,对所有属于该命名空间的进程都是可见的。
init_nsproxy定义了初始的全局命名空间,其中维护了指向各子系统初始的命名空间对象的指针。在kernel/nsproxy.c文件内有
struct nsproxy init_nsproxy = { .count = ATOMIC_INIT(1), .uts_ns = &init_uts_ns,#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC) .ipc_ns = &init_ipc_ns,#endif .mnt_ns = NULL, .pid_ns_for_children = &init_pid_ns,#ifdef CONFIG_NET .net_ns = &init_net,#endif#ifdef CONFIG_CGROUPS .cgroup_ns = &init_cgroup_ns,#endif#ifdef CONFIG_TIME_NS .time_ns = &init_time_ns, .time_ns_for_children = &init_time_ns,#endif};
UTS命名空间几乎不需要特别的处理,因为它只需要简单量,没有层次组织。所有相关信息都汇集到下列结构的一个实例中。在utsname.h文件内:
struct uts_namespace { struct new_utsname name; struct user_namespace *user_ns; struct ucounts *ucounts; struct ns_common ns;} __randomize_layout;
uts_namespace所提供的属性信息本身包含在struct new_utsname中:
struct oldold_utsname { char sysname[9]; char nodename[9]; char release[9]; char version[9]; char machine[9];};#define __NEW_UTS_LEN 64struct old_utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65];};struct new_utsname { char sysname[__NEW_UTS_LEN + 1]; char nodename[__NEW_UTS_LEN + 1]; char release[__NEW_UTS_LEN + 1]; char version[__NEW_UTS_LEN + 1]; char machine[__NEW_UTS_LEN + 1]; char domainname[__NEW_UTS_LEN + 1];}
各个字符串分别存储了系统的名称( Linux…)、内核发布版本、机器名,等等。使用uname工具可以取得这些属性的当前值,也可以在/proc/sys/kernel/中看到
z@z-virtual-machine:~$ cat /proc/sys/kernel/ostype Linux z@z-virtual-machine:~$ cat /proc/sys/kernel/osrelease5.3.0-40-generic
初始设置保存在init_uts_ns中,在init/version.c文件内:
struct uts_namespace init_uts_ns = { .ns.count = REFCOUNT_INIT(2), .name = { .sysname = UTS_SYSNAME, .nodename = UTS_NODENAME, .release = UTS_RELEASE, .version = UTS_VERSION, .machine = UTS_MACHINE, .domainname = UTS_DOMAINNAME, }, .user_ns = &init_user_ns, .ns.inum = PROC_UTS_INIT_INO,#ifdef CONFIG_UTS_NS .ns.ops = &utsns_operations,#endif};
相关推荐:《Linux视频教程》
以上がLinux 名前空間について知っておくべきことの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。