Especially when building cloud-native applications, we tend to develop applications that run in any environment. We design components, so we can run them with or without container technologies to ensure we can host the application on different application platforms. However, sometimes we may have to determine if our applications are running inside a Docker container or not. This allows us to take particular actions at runtime without adding additional environment variables or configuration values (state). Every container has a .dockerenv file in the file system’s root. That said, we can quickly check for the existence of that file to determine reliably if our application runs inside a container or not. For demonstration purposes, this post shows how to determine if the application is executed in a container using Go and Rust.

Check if your application is running in a container using Go

First, let’s take a look at Go. In Go, we need to import the os package and use the Stat function to reliably check if the actual application is executed within a Docker container or not:

func isRunningInContainer() bool {
    if _, err := os.Stat("/.dockerenv"); err != nil {
        return false
    }
    return true
}

To verify this, let’s build a small sample application, that we can run directly on our host system and inside of a container.

Implement the sample application with Go

Create and initialize a Go module:

# make and navigate to a new folder
take verify-with-go

# Create a go.mod file
go mod init verify-with-go

# Create a main.go file
touch main.go

# Open in VSCode
code .

Let’s put the following Go code in main.go:

package main

import (
    "fmt"
    "os"
)

func main() {
    if isRunningInContainer() {
        fmt.Println("Running in a container")
        os.Exit(0)
    }
    fmt.Println("Not running in a container")
}

func isRunningInContainer() bool {
    if _, err := os.Stat("/.dockerenv"); err != nil {
        return false
    }
    return true
}

Having this in place, we can run the application locally using go run main.go, resulting in printing the Not running in a container message. So far so good. Now let’s containerize the application and check if it also works inside of a container.

Containerize the Go sample

We can containerize the Go sample by using the following Dockerfile:

FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git
WORKDIR $GOPATH/src/mypackage/myapp/
COPY . .
RUN go get -d -v
RUN go build -o /go/bin/verify-with-go
FROM scratch
COPY --from=builder /go/bin/verify-with-go /go/bin/verify-with-go
ENTRYPOINT ["/go/bin/verify-with-go"]

Let’s build and run the container locally with docker CLI (or comparable tooling):

# build the container image
docker build . -t verify-with-go:local

# docker run --rm verify-with-go:local
Running in a container

As you can see, we got the message Running in a container printed to the terminal once we’ve built the container image and executed the container.

Check if your application is running in a container using Rust

Let’s take a look at Rust. Rust’s standard library also comes with the necessary batteries included. We can use the the Path struct from the path module to check for the .dockerenv file:

pub fn is_running_in_container() -> bool {
    Path::new("/.dockerenv").exists()
}

Again we build a small sample application to verify everything works as expected.

Implement the sample application with Rust

To create a new Rust project, we use cargo which comes with your Rust installation:

# make and navigate to a new folder
take verify-with-rust

# Create a new binary project with cargo
cargo init --bin . --name verify-with-rust

# Open in VSCode
code .

Find and open the src/main.rs file. Modify the file content to match the following snippet:

use std::path::Path;

fn main() {
  if is_running_in_container() {
    println!("Running in a container");
    return;
  }
  println!("Not running in a container");
}

pub fn is_running_in_container() -> bool {
  Path::new("/.dockerenv").exists()
}

Containerize the Rust sample

To containerize the Rust sample, add a Dockerfile with the following content:

FROM rust:latest AS builder
RUN rustup target add x86_64-unknown-linux-musl
RUN apt update && apt install -y musl-tools musl-dev
RUN update-ca-certificates
WORKDIR /app
COPY ./ ./
RUN cargo build --release --target x86_64-unknown-linux-musl

FROM alpine
WORKDIR /app
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/verify-with-rust .
CMD ["./verify-with-rust"]

Build and run the container locally. Again, you can use docker CLI or any comparable tooling:

# build the container image
docker build . -t verify-with-rust:local

# docker run --rm verify-with-rust:local
Running in a container

As you can see, we got the message Running in a container printed to the terminal once we’ve built the image and executed the verify-with-rust:local container.

What about Windows containers

Unfortunately, Windows containers are - again - an exception here. Windows containers do not contain a .dockerenv in the filesystem’s root.

Recap

As seen in both samples, we can quickly check if your application is running inside a container using primitive functionalities provided by standard libraries in Go and Rust. That said, there is no need to add 3rd party dependencies to your application to determine if the process is currently executed in a container or not.

What we covered

Over the course of this article we covered:

  • 💡 Learned how to check if an application is executed within a container
  • 👷🏻‍♂️ Saw how to check if running inside of container with Go(lang)
  • 👷🏻‍♂️ Saw how to check if running inside of container with Rust
  • 🧐 Once again recognized that Windows containers are “special”