{"id":49901,"date":"2025-07-01T05:27:33","date_gmt":"2025-07-01T05:27:33","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=49901"},"modified":"2025-07-01T05:27:33","modified_gmt":"2025-07-01T05:27:33","slug":"understanding-pid-1-physical-servers-virtual-machines-and-containers","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/understanding-pid-1-physical-servers-virtual-machines-and-containers\/","title":{"rendered":"Understanding PID 1: Physical Servers, Virtual Machines, and Containers"},"content":{"rendered":"\n<p>Here\u2019s a <strong>comprehensive, practical, and explanatory tutorial<\/strong> on the topic of PID 1 in physical servers, virtual machines, and containers, including <strong>why PID 1 is special in containers<\/strong>, how it relates to the Linux process tree, and how you can experiment with it using Ubuntu containers.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Understanding PID 1: Physical Servers, Virtual Machines, and Containers<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>Every modern computing environment\u2014whether it\u2019s a physical server, a virtual machine, or a container\u2014relies on a process management system. At the core of this system is a very special process known as <strong>PID 1<\/strong> (Process ID 1). Understanding PID 1\u2019s role and behavior is essential for anyone working with Linux systems, especially in the age of containers and cloud-native applications.<\/p>\n\n\n\n<p>This tutorial covers:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The meaning and role of PID 1 in different environments<\/li>\n\n\n\n<li>Why PID 1 is unique and important<\/li>\n\n\n\n<li>How PID 1 differs between physical\/virtual servers and containers<\/li>\n\n\n\n<li>Practical hands-on: Experimenting with PID 1 in an Ubuntu container<\/li>\n\n\n\n<li>Best practices and runtime considerations<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What is PID 1?<\/h2>\n\n\n\n<p>In Linux and UNIX-like operating systems, every process is assigned a <strong>unique process ID<\/strong> (PID). PID 1 is always reserved for the very first process that the kernel starts during boot. This process is special:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>It acts as the <strong>init process<\/strong>\u2014the ancestor of all other processes.<\/li>\n\n\n\n<li>It is responsible for reaping orphaned child processes (adopting and cleaning up \u201czombie\u201d processes).<\/li>\n\n\n\n<li>If PID 1 exits, the system will typically halt or panic (in traditional servers\/VMs).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">PID 1 in Different Environments<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. <strong>Physical Server<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Boot Process:<\/strong> When a physical server boots, the kernel loads into memory and the very first user-space program it starts is <strong>init<\/strong> (historically <code>\/sbin\/init<\/code>, now often <code>systemd<\/code> or another init system).<\/li>\n\n\n\n<li><strong>PID 1 Role:<\/strong> The init system is always PID 1.<\/li>\n\n\n\n<li><strong>Responsibilities:<\/strong> It starts all other system services, manages the system lifecycle, and handles orphaned processes.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. <strong>Virtual Machine<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Boot Process:<\/strong> When a VM starts, it simulates a physical machine. The guest OS kernel starts, and again, the first user-space process is init\/systemd with PID 1.<\/li>\n\n\n\n<li><strong>PID 1 Role:<\/strong> Same as a physical server\u2014runs the OS service manager.<\/li>\n\n\n\n<li><strong>Responsibilities:<\/strong> Identical to physical servers.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3. <strong>Container<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Boot Process:<\/strong> When a container starts, it does <strong>not<\/strong> boot a full OS. Instead, it starts a process specified in the container image (like <code>\/bin\/bash<\/code>, <code>nginx<\/code>, or your app) <strong>directly<\/strong> as PID 1 in a new namespace.<\/li>\n\n\n\n<li><strong>PID 1 Role:<\/strong> Whatever command you specify in your <code>Dockerfile<\/code> or <code>docker run<\/code> becomes PID 1 inside the container!<\/li>\n\n\n\n<li><strong>Responsibilities:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Must reap zombie processes (or else container leaks processes).<\/li>\n\n\n\n<li>If it exits, the entire container stops.<\/li>\n\n\n\n<li><strong>Can be any executable<\/strong> (unlike physical\/VM, where it must be init\/systemd).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why is PID 1 Special in Containers?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Process Reaping:<\/strong> Only PID 1 receives \u201corphaned\u201d (zombie) child processes. If PID 1 does not handle them, your container can get filled with zombies, causing resource leaks.<\/li>\n\n\n\n<li><strong>Signal Handling:<\/strong> PID 1 in Linux does not handle signals like other processes. For example, by default it ignores <code>SIGTERM<\/code> and <code>SIGINT<\/code> unless explicitly coded to handle them.<\/li>\n\n\n\n<li><strong>App as PID 1:<\/strong> In containers, your application (say, a Node.js or Python app) is often PID 1, so it needs to be coded carefully or wrapped with a process manager (like <code>tini<\/code> or <code>dumb-init<\/code>).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Table: Comparison of PID 1 in Environments<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Environment<\/th><th>PID 1 Process<\/th><th>Usually Runs<\/th><th>Can be Any Executable?<\/th><th>Responsibilities<\/th><\/tr><\/thead><tbody><tr><td>Physical Server<\/td><td>init\/systemd<\/td><td>Kernel booted OS<\/td><td>No<\/td><td>System\/service management, reaping<\/td><\/tr><tr><td>Virtual Machine<\/td><td>init\/systemd<\/td><td>Kernel booted OS<\/td><td>No<\/td><td>System\/service management, reaping<\/td><\/tr><tr><td>Container<\/td><td>Entry CMD\/ENTRYPOINT<\/td><td>Your app\/bash<\/td><td><strong>Yes<\/strong><\/td><td>Running the app, reaping, signal mgmt<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Hands-On: Experimenting with PID 1 in Ubuntu Containers<\/h2>\n\n\n\n<p>Let\u2019s see all of this <strong>in action<\/strong>!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Prerequisites<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Docker installed<\/li>\n\n\n\n<li>An Ubuntu image (or any Linux image)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 1: Start a Container with Default Shell<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker run -it ubuntu bash\n<\/code><\/span><\/pre>\n\n\n<p>Inside the container, run:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">ps -ef\n<\/code><\/span><\/pre>\n\n\n<p>You\u2019ll see something like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">UID<\/span>   <span class=\"hljs-selector-tag\">PID<\/span>  <span class=\"hljs-selector-tag\">PPID<\/span>  <span class=\"hljs-selector-tag\">C<\/span> <span class=\"hljs-selector-tag\">STIME<\/span> <span class=\"hljs-selector-tag\">TTY<\/span>          <span class=\"hljs-selector-tag\">TIME<\/span> <span class=\"hljs-selector-tag\">CMD<\/span>\n<span class=\"hljs-selector-tag\">root<\/span>    1     0  0 00<span class=\"hljs-selector-pseudo\">:00<\/span> ?        00<span class=\"hljs-selector-pseudo\">:00<\/span><span class=\"hljs-selector-pseudo\">:00<\/span> <span class=\"hljs-selector-tag\">bash<\/span>\n<span class=\"hljs-selector-tag\">root<\/span>   21     1  0 00<span class=\"hljs-selector-pseudo\">:01<\/span> ?        00<span class=\"hljs-selector-pseudo\">:00<\/span><span class=\"hljs-selector-pseudo\">:00<\/span> <span class=\"hljs-selector-tag\">ps<\/span> <span class=\"hljs-selector-tag\">-ef<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Notice: <strong><code>bash<\/code> is running as PID 1<\/strong>!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 2: Start a Container Running Another App as PID 1<\/strong><\/h3>\n\n\n\n<p>Let\u2019s run <code>sleep<\/code> as the only process:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker run -it ubuntu sleep 300\n<\/code><\/span><\/pre>\n\n\n<p>In another terminal, find the running container ID and exec into it:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">docker exec -it <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">container_id<\/span>&gt;<\/span> ps -ef\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Output:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">UID<\/span>   <span class=\"hljs-selector-tag\">PID<\/span>  <span class=\"hljs-selector-tag\">PPID<\/span>  <span class=\"hljs-selector-tag\">C<\/span> <span class=\"hljs-selector-tag\">STIME<\/span> <span class=\"hljs-selector-tag\">TTY<\/span>          <span class=\"hljs-selector-tag\">TIME<\/span> <span class=\"hljs-selector-tag\">CMD<\/span>\n<span class=\"hljs-selector-tag\">root<\/span>    1     0  0 00<span class=\"hljs-selector-pseudo\">:02<\/span> ?        00<span class=\"hljs-selector-pseudo\">:00<\/span><span class=\"hljs-selector-pseudo\">:00<\/span> <span class=\"hljs-selector-tag\">sleep<\/span> 300\n<span class=\"hljs-selector-tag\">root<\/span>    7     1  0 00<span class=\"hljs-selector-pseudo\">:03<\/span> ?        00<span class=\"hljs-selector-pseudo\">:00<\/span><span class=\"hljs-selector-pseudo\">:00<\/span> <span class=\"hljs-selector-tag\">ps<\/span> <span class=\"hljs-selector-tag\">-ef<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, <strong><code>sleep<\/code> is PID 1<\/strong>!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 3: Start a Container with systemd\/init as PID 1 (Advanced)<\/strong><\/h3>\n\n\n\n<p>This is not typical in containers, but possible:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">docker run --privileged -d --name myinit ubuntu \/sbin\/init\ndocker exec -it myinit ps -ef\n<\/code><\/span><\/pre>\n\n\n<p>Now, <code>\/sbin\/init<\/code> (or <code>\/lib\/systemd\/systemd<\/code> in some images) is PID 1.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Understanding Zombie Reaping<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In servers\/VMs, init handles zombie reaping automatically.<\/li>\n\n\n\n<li>In containers, if your app (PID 1) doesn\u2019t reap children, zombies accumulate.<\/li>\n\n\n\n<li><strong>Best practice:<\/strong> Use a process manager (e.g., <a href=\"https:\/\/github.com\/krallin\/tini\" target=\"_blank\" rel=\"noopener\">tini<\/a>, <a href=\"https:\/\/github.com\/Yelp\/dumb-init\" target=\"_blank\" rel=\"noopener\">dumb-init<\/a>) as PID 1 or code your app to reap.<\/li>\n<\/ul>\n\n\n\n<p>Example Dockerfile:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">FROM<\/span> <span class=\"hljs-selector-tag\">ubuntu<\/span>\n<span class=\"hljs-selector-tag\">RUN<\/span> <span class=\"hljs-selector-tag\">apt-get<\/span> <span class=\"hljs-selector-tag\">update<\/span> &amp;&amp; <span class=\"hljs-selector-tag\">apt-get<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">-y<\/span> <span class=\"hljs-selector-tag\">tini<\/span>\n<span class=\"hljs-selector-tag\">ENTRYPOINT<\/span> <span class=\"hljs-selector-attr\">&#91;<span class=\"hljs-string\">\"\/usr\/bin\/tini\"<\/span>, <span class=\"hljs-string\">\"--\"<\/span>]<\/span>\n<span class=\"hljs-selector-tag\">CMD<\/span> <span class=\"hljs-selector-attr\">&#91;<span class=\"hljs-string\">\"your-app\"<\/span>]<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Best Practices for PID 1 in Containers<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Use a minimal init system<\/strong> (like tini) to handle signals and zombies.<\/li>\n\n\n\n<li>If your app is PID 1, ensure it handles SIGTERM, SIGINT, and reaps zombies.<\/li>\n\n\n\n<li>Remember: When PID 1 exits, the container stops!<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Summary<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>PID 1<\/strong> is the \u201cinit\u201d process in every Linux environment.<\/li>\n\n\n\n<li>In servers\/VMs, it\u2019s always the system init (systemd, etc.).<\/li>\n\n\n\n<li>In containers, <strong>your app becomes PID 1<\/strong>\u2014with all its responsibilities!<\/li>\n\n\n\n<li>Failing to manage PID 1 properly in containers can lead to unclean shutdowns and resource leaks.<\/li>\n\n\n\n<li><strong>Always test and experiment:<\/strong> Try running different apps as PID 1 in a container, and use process managers for production workloads.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><\/h2>\n","protected":false},"excerpt":{"rendered":"<p>Here\u2019s a comprehensive, practical, and explanatory tutorial on the topic of PID 1 in physical servers, virtual machines, and containers, including why PID 1 is special in containers, how it&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-49901","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49901","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=49901"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49901\/revisions"}],"predecessor-version":[{"id":49902,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49901\/revisions\/49902"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=49901"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=49901"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=49901"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}