In this lesson you'll get an introduction to what a container really is, by writing a basic container in Go. You'll see how a container is really just a Linux process, with a restricted view.
Congratulations, you built your own container!
You now know that a container is really just a Linux process that has a restricted view.
- Namespaces limit what the container process can see - for example, giving the container an isolated set of process IDs.
- Changing the root limits the set of files and directories that the container can see.
There is a third construct that limits the resources that a container has access to: control groups or cgroups. There are different types of cgroup for different types of resources: memory, CPU, process, I/O and more. The cgroup controls how much of that resource is available to its members. A process is assigned to a cgroup so that it can only have access to that limited resource.
Notes and further reading
- Find a version of this code at lizrice/containers-from-scratch on GitHub
- See cgroups in action in this video

Steps
Write a container from scratch
Execute an arbitrary command
We're going to create a program that can run an arbitrary command in a containerized process. This will be an illustration of what happens when you do a docker run
command.
This isn't going to be production-quality code!
First let's start by writing some code that will execute an arbitrary command.
package main import ( "fmt" "os" "os/exec" ) func main() { // We expect "run" as the first argument switch os.Args[1] { case "run": run() default: panic("Bad argument") } fmt.Println("== Finished ==") } func run() { // Arguments 2 onwards are the arbitrary command we're going to run fmt.Printf("Running %v\n", os.Args[2:]) // Set up a struct that describes the command we want to run cmd := exec.Command(os.Args[2], os.Args[3:]...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr // This is where we run the command err := cmd.Run() if err != nil { panic(fmt.Sprintf("running: %v\n", err)) } }
Build and run this command:
go run main.go run echo hello
go run main.go
builds and runs the programrun
is argument 1 - you'll see why we want this in a later stepecho hello
is the command we want to run
At this stage there is no containerization - your program runs the command in a regular Linux process. The command echo hello
gets executed, then the program completes.
Note that you can also run a shell as your arbitrary command:
go run main.go run bash
You'll see a command prompt, but notice that the == Finished ==
message doesn't get output straight way. The program is blocked while the shell process in running. You'll only see the == Finished ==
message when you exit that shell:
exit
Use ps
to check what is running
You can use a second terminal window to confirm what's running. First check what processes are running under your user ID:
ps -af
If nothing else is running, you should only see output for the ps
command you were just running.
Run your program again (this will run in the first terminal window):
go run main.go run bash
While your program is still running, check the processes again:
ps -af
You should see four processes running:
go run main.go run bash
is the command you executed to compile and then run your program- go compiled and wrote the executable to the /tmp directory. You should be able to see that executable in the process list
- Your program cloned a new process to run
bash
- You should also see the process for
ps
that you just ran
Finally, quit out of your program:
exit
Want to check what's still running?
ps -af
Next step
In the next step you will start to containerize the process by giving it its own namespace for its host name.
You’ll love Katacoda

Guided Path
Knowing what you need to know is the hardest part. Our guided pathways help build your knowledge around real-world scenarios.

Learn By Doing
The best way to learn is by doing. All our tutorials are interactive with pre-configured live environments ready for you to use.

Stay up-to-date
It's a competitive industry. Your skills need to keep up with the latest approaches. Katacoda keeps your skills up-to-date.
You’ll love Katacoda

Guided Path
Knowing what you need to know is the hardest part. Our guided pathways help build your knowledge around real-world scenarios.

Learn By Doing
The best way to learn is by doing. All our tutorials are interactive with pre-configured live environments ready for you to use.

Stay up-to-date
It's a competitive industry. Your skills need to keep up with the latest approaches. Katacoda keeps your skills up-to-date.