Linux for the cloud · Lesson 1 of 14 · about 20 minutes

What Linux is, and why the cloud runs on it

Linux is two things: a kernel, and the distribution built around it. Asked from the inside, a Mac says Darwin, three different Docker containers all report the same Linux kernel, and a real cloud server says Debian. Along the way, the same command behaves differently on a Mac, and a tool you'd expect is missing from a slim container.

By the end you'll know

  • The difference between a kernel and a distribution
  • Why a Mac isn't Linux, even though its terminal looks the same
  • Why a container has no kernel of its own
  • How to find out what any machine is running, in three commands
  • Why the same command can behave differently from one machine to the next

The problem: "it's Linux" isn't one thing

Almost every cloud server runs Linux. So does almost every container, every Kubernetes node, and the machines behind most of the websites you use. When something breaks on any of them, the place you end up is a Linux shell.

But "Linux" covers a lot. A tiny container image, a full Ubuntu server and the machine running a Kubernetes cluster are all Linux, and they don't all have the same tools. A Mac's terminal looks almost identical to all of them and isn't Linux at all. Knowing exactly what you're standing on is the first step in fixing anything, and it takes three commands to find out.

A kernel, and a distribution

Linux, strictly speaking, is a kernel: the core program that talks to the hardware and runs everything else. It decides which program gets the processor next, hands out memory, reads and writes the disk, and sends data over the network. You never use the kernel directly. Every program you run asks it to do things on its behalf.

A kernel on its own isn't much use. You also need a shell to type into, commands like ls and grep, a way to install software, and sensible settings. A distribution bundles all of that around the kernel. Ubuntu, Debian, Alpine, Red Hat Enterprise Linux and Amazon Linux are all distributions. They share the Linux kernel, and differ in which tools they include, how they install software and how long each version is supported.

Think of it like a car. The kernel is the engine. The distribution is everything else: the seats, the dashboard, the controls. Two cars can share an engine and still feel completely different to drive.

Linus Torvalds wrote the first Linux kernel in 1991, and it's been developed in the open ever since. Many of the everyday commands around it come from a separate project, GNU, which is why you'll sometimes see "GNU/Linux" in a distribution's name.

Why the cloud runs on it

A few reasons, which reinforce each other:

  • It's free to run. There's no license fee per server, which matters when you run thousands of them.
  • It's open. Anyone can read the code, fix it and adapt it, so cloud providers can tune it for their own hardware.
  • Containers are a Linux feature. Docker and Kubernetes are built on parts of the Linux kernel that keep programs apart from each other. A Linux container needs a Linux kernel to run on.
  • The tools and skills are everywhere. Most server software is written for Linux first, and most of the people running servers know it.

So learning Linux isn't learning one product. It's learning the ground almost everything in the cloud stands on.

Ask your own machine

Start with the machine in front of you. The examples in this track were run on a Mac, so that's what the output shows; Windows and Linux are covered just below. In a Mac's Terminal:

BASH
uname -s
uname -r
sw_vers
OUTPUT
Darwin
25.6.0
ProductName: macOS
ProductVersion: 26.6.2
BuildVersion: 25G83
  • uname -s prints the kernel's name. uname stands for "Unix name", and -s asks for the system name.
  • uname -r prints the kernel's version, its release.
  • sw_vers ("software version") prints the macOS version. It only exists on a Mac.

A Mac's kernel is Darwin, Apple's own. It comes from the Unix family, the same family Linux was modeled on, which is why the terminal, the folders and many commands look the same. But it isn't Linux, and that will matter in a moment.

On Windows or Linux?

The rest of the track runs inside Linux containers, so it works the same on any computer. Only this first step differs.

MacWindowsLinux
What am I running?uname -s, uname -r and sw_vers in Terminalsysteminfo | findstr /B /C:"OS Name" /C:"OS Version" in PowerShelluname -s, uname -r and cat /etc/os-release
Getting a Linux shellDocker DesktopWSL 2, or Docker DesktopYou're already in one; Docker is optional
Whose kernel do containers use?Docker Desktop's hidden virtual machineWSL 2's virtual machineThe computer's own

On Windows, uname and sw_vers don't exist in PowerShell or Command Prompt, because Windows isn't from the Unix family at all. But Windows can run Linux well, through WSL (Windows Subsystem for Linux). Version 2 runs a real Linux kernel in a small hidden virtual machine: run wsl --install in PowerShell, restart, and you have an Ubuntu shell where every command in this track works. Inside it, uname -r usually shows a version ending in microsoft-standard-WSL2, the same idea as the linuxkit you'll see below on a Mac. Docker Desktop on Windows uses WSL 2 behind the scenes, so the docker run commands work the same.

On Linux, you're already there. uname works as shown, sw_vers gives "command not found" because it's Mac-only, and cat /etc/os-release tells you which distribution you have. Docker on Linux needs no hidden virtual machine, so containers use your computer's own kernel directly. That makes the next section's point easier to see: uname -r inside a container gives exactly the same answer as outside it.

Ask a Linux machine

Docker gives you a Linux machine in one command. Every command in this track runs inside a container like this, so there's nothing to install and nothing to break on your own computer. On a Mac or Windows, Docker Desktop needs to be running; on Linux, Docker Engine does the same job.

BASH
docker run --rm ubuntu:24.04 uname -s
docker run --rm ubuntu:24.04 uname -r
docker run --rm ubuntu:24.04 cat /etc/os-release

Each line starts a new Ubuntu container, runs one command in it and, because of --rm, deletes the container afterwards. The first run downloads the Ubuntu image, a few tens of megabytes.

OUTPUT
Linux
7.0.14-linuxkit
PRETTY_NAME="Ubuntu 24.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.5 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo

(The image download lines are left out.)

Two answers, and they don't match.

  • The kernel is Linux 7.0.14-linuxkit. Not an Ubuntu kernel at all.
  • The distribution is Ubuntu 24.04.5 LTS. /etc/os-release is a small text file every modern distribution keeps, saying what it is. It's the Linux version of sw_vers. LTS means Long Term Support: a release that gets security updates for years, which is why servers use them. ID_LIKE=debian says Ubuntu is built on Debian, another distribution.

The kernel and the distribution came from two different places, and that's the key to what a container is.

A container has no kernel of its own

A container isn't a small virtual computer. It's a normal program, kept apart from everything else by the kernel, and it shares the kernel of the machine it runs on. The image brings the distribution's files and tools; the kernel comes from the host.

A Mac's kernel is Darwin, which can't run Linux programs. So Docker Desktop quietly runs a small Linux virtual machine in the background, and every container shares its kernel. The linuxkit in the kernel's version is the sign: that's the kernel of the hidden machine.

Three different distributions show it:

BASH
for img in ubuntu:24.04 alpine:3.20 python:3.13-slim; do echo "== $img"; docker run --rm $img sh -c 'grep PRETTY_NAME /etc/os-release; uname -r'; done

The for loop runs the same two commands in three images: grep picks out the line with the distribution's name, and uname -r prints the kernel.

OUTPUT
== ubuntu:24.04
PRETTY_NAME="Ubuntu 24.04.5 LTS"
7.0.14-linuxkit
== alpine:3.20
PRETTY_NAME="Alpine Linux v3.20"
7.0.14-linuxkit
== python:3.13-slim
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
7.0.14-linuxkit

(The download lines for Alpine and Python are left out.)

Three distributions, one kernel. And one surprise: the official Python image is Debian underneath, with Python added on top. A lot of images you'll use are a familiar distribution wearing a different name.

Pick each one, and see what it's made of:

Try it: what is it, underneath?

  1. What you runbash, as process 1
  2. DistributionUbuntu 24.04.5 LTS
  3. KernelLinux 7.0.14-linuxkit
  4. Running onDocker Desktop’s hidden Linux virtual machine, on the Mac

The container brings Ubuntu’s files and tools, but not a kernel. It borrows the kernel of the virtual machine Docker Desktop runs.

Inside a Linux machine

So far each container ran one command and stopped. Add -it (interactive, with a terminal) and run a shell instead, and you're inside:

BASH
docker run -it --rm ubuntu:24.04 bash

The prompt changes to something like root@b31e55420ea1:/#. Everything you type now runs inside the container:

BASH
whoami
hostname
ls /
cat /proc/1/cmdline; echo
ps
exit
OUTPUT
root
b31e55420ea1
bin  boot  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
bash
    PID TTY          TIME CMD
      1 pts/0    00:00:00 bash
     13 pts/0    00:00:00 ps

Each line says something about where you are:

  • root: you're the administrator, the user allowed to do anything. That's the default in a container, and a bad idea on a real server, as the "Permissions and users" lesson explains.
  • b31e55420ea1: the machine's name is the container's ID.
  • ls /: the standard Linux folder layout, the same on every distribution. etc holds settings, var holds logs and other changing data, home holds people's folders. Lesson 2 walks through them.
  • Process 1 is bash. The first process on a Linux system is special, because it starts everything else. On a full server, it's a program called systemd, which starts and looks after every service. A container runs only what you asked for, which here is a shell.
  • ps lists running processes: just your shell and ps itself. A real server has hundreds.

exit leaves the shell, and the container is deleted.

Break it on purpose

Two things that work in one place and not another.

The same command, two different programs. sed edits text, and Lesson 4 uses it a lot. Ask it its version, on a Mac and in Ubuntu:

BASH
sed --version
docker run --rm ubuntu:24.04 sed --version
OUTPUT
sed: illegal option -- -
usage: sed script [-EHalnru] [-i extension] [file ...]
sed [-EHalnu] [-i extension] [-e script] ... [-f script_file] ... [file ...]
sed (GNU sed) 4.9
Packaged by Debian
Copyright (C) 2022 Free Software Foundation, Inc.

(The rest of GNU sed's message is left out.)

The Mac's sed doesn't even understand the question. It's BSD sed, from the same Unix family as Darwin. Ubuntu's is GNU sed. They share a name and most of their features, and differ in the details. Look at the Mac's usage line: -i extension. On a Mac, sed -i (edit a file in place) always expects a backup file extension, so editing without a backup needs an empty one: sed -i ''. On Linux, sed -i takes nothing. A script written on a Mac can fail on a Linux server for exactly this reason, and the other way round. On Linux, or in WSL on Windows, sed --version works fine, because that's GNU sed too; the trap is for scripts that move between a Mac and Linux.

A tool that isn't there. Slim images leave things out to stay small:

BASH
docker run --rm python:3.13-slim ps
OUTPUT
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "ps": executable file not found in $PATH

Read the end of the error: executable file not found in $PATH. PATH is the list of folders the system searches for a program, and ps isn't in any of them. It's simply not installed. Fewer tools means a smaller image and less for an attacker to use, and it means the tool you reach for while troubleshooting may not exist. Lesson 6 shows how to see processes without ps.

On a real server

Containers on a laptop are good practice, but the servers they end up on are real Linux machines with their own kernel. Here's one: a node in a Kubernetes cluster on a cloud provider, the kind of server that runs containers in production. Asking the cluster what it is, with only the two columns that matter and no server names or addresses:

BASH
kubectl get nodes -o custom-columns=OS:.status.nodeInfo.osImage,KERNEL:.status.nodeInfo.kernelVersion
OUTPUT
OS                             KERNEL
Debian GNU/Linux 13 (trixie)   6.12.90+deb13.1-amd64

Debian 13, the same distribution as the python:3.13-slim image, this time with a real Debian kernel. And a different kernel version from the one on the laptop: 6.12 on the server, 7.0 in Docker Desktop. A Python app built on that image runs on both. Most of the time that makes no difference, because programs talk to the kernel through an interface that changes very slowly. But it's worth remembering that "it worked on my laptop" was tested on a different kernel from the one in production.

The same goes the other way. Many people run scripts on a Mac they treat as a small server. A script written there can use Mac-only commands, like caffeinate, which stops a Mac from going to sleep, and would fail on a Linux server where that command doesn't exist.

Spot the problem

Three situations. Work out what's wrong before you read the explanation.

The script that worked yesterday. A developer writes a script on a Mac that edits a settings file with sed -i '' 's/old/new/' config.txt. It works. On the Linux build server, it fails, complaining that it can't read a file called s/old/new/. What's going on? Mac sed and Linux sed are different programs. GNU sed takes the '' as the editing command, then treats s/old/new/ as the name of a file to edit. On Linux, the same edit is sed -i 's/old/new/' config.txt.

The missing command. Someone opens a shell in a production container to see what's running, types ps, and gets "command not found". Is the container broken? No. It's a slim image, and ps was never installed. The information is still there, in /proc; only the tool is missing.

"It's just Linux." A team tests an app in an Alpine container on their laptops, then deploys it on Ubuntu servers, and is surprised when a command behaves differently. What did they assume? That all Linux is the same. Alpine and Ubuntu share a kernel family, and ship different tools and different versions of them. Check the distribution with cat /etc/os-release, and test on the one you'll run.

Keep this

To find outRun
Which kerneluname -s
The kernel's versionuname -r
Which distribution, and its versioncat /etc/os-release
Which macOS version (Mac only)sw_vers
Which user you arewhoami
The machine's namehostname
What process 1 iscat /proc/1/cmdline; echo
Run one command in a throwaway Linux containerdocker run --rm ubuntu:24.04 <command>
Get a shell in onedocker run -it --rm ubuntu:24.04 bash

Where you are now

Linux is a kernel, the core program that runs everything else, and a distribution is the kernel plus everything around it: commands, settings and a way to install software. A Mac isn't Linux; its kernel is Darwin, a cousin from the Unix family. A container isn't a small computer: it brings a distribution and borrows the host's kernel, which is why three different containers reported the same one. The same command can be a different program on a different system, as sed showed, and a tool can be missing entirely, as ps was. Lesson 2 goes inside for real: moving around the file system, and what each of those folders in / is for.

Check yourself

  1. What does the Linux kernel do?

  2. What is a distribution?

  3. Three containers all reported kernel 7.0.14-linuxkit. Why?

  4. Why did 'sed --version' fail on the Mac?

  5. What does 'executable file not found in $PATH' mean?

  6. Which file tells you which distribution you're on?

Key terms

  • Kernel: the core program that controls the hardware and runs every other program.
  • Distribution: the kernel plus the tools, settings and package manager around it, such as Ubuntu or Debian.
  • Darwin: the kernel macOS is built on; a Unix relative of Linux, not Linux itself.
  • Container: a program kept apart from others by the kernel, with its own files, sharing the host's kernel.
  • Image: the files a container starts from, usually a distribution plus an app.
  • LTS (Long Term Support): a release that gets security updates for several years.
  • Process 1: the first program a Linux system starts, which starts everything else.
  • PATH: the list of folders searched when you type a command's name.

Go deeper

  • Try uname -m on your own computer and in a container. It prints the processor type the kernel is running on. Do they match?
  • Compare an image you use at work, or one from Docker Hub: run cat /etc/os-release inside it and find out what it really is.
  • The Linux Command Line (opens in a new tab), a free book that starts from zero.
  • Docker Lesson 1, What containers solve, for why containers exist at all.