Post

Installing containerized apps on airgapped systems

Shipping Docker images to an airgapped system can be challenging due to no internet connectivity. Let see how we can ship `docker` images to an airgapped system.

Installing containerized apps on airgapped systems

Evolution

Shipping Software to a client has been a long standing issue in the Software industury. I remember when I got my first computer, We used to purchase software on CD-ROMs and install them on our computer. At that time, Companies used to bundle all the dependencies into the CD-ROMs along with the main software.

As internet become popular, many companies started to allow users to download their software over internet. Over many years, the softwares started becoming more complex and bulkier. It was not easy to bundle everything into a single package. Companies started to split the software into multiple packages and prompting their users to install the dependencies separately.

This resulted in another problem where companies started to request for specific versions of the dependencies and customers could not install other softwares which required different versions of the same dependency.

Docker to save the day

I remember when I was working on a project where everything worked on my machine but would not work on clients machine. Later I found that I missed listing a dependency in the documentation. This reminds me of a popular meme on Docker:

Docker meme Docker meme

After few months I discovered docker and proposed to use docker to ship our application. With docker we were able to ship our application along with its dependencies without conflicting with any software installed on the host machine.

What is docker?

Docker is a platform for developing, shiping and running applications. Docker combines functionalities provided by chroot with cgroups to provide isolation between the container and the host machine or the underlying infrastrucute. Container provides an ecosystem parallel to a VM but without the overhead of a VM.

Today we have many other applications like containerd, podman, colima, rancher desktop etc competing with docker.

Airgapped Systems on the rise

Many companies have switched to ship their application via containers due to the isolation provided by it. This means that companies have a new challenge of managing the security of the container, fixing any CVEs or vulnerabilities in the containers or issues in software installed in the containers.

Imagine if an Attacker gains access to a crucial medical system and causes harm to the patients because the Software vendor did not fix the CVEs or vulnerabilities in their container. Due to this many companies have started to airgap their crucial systems to protect their systems from malicious actors.

Installing a containerized application on an Airgapped system

On a machine with internet access

  • Open terminal and pull the image of the application you want to install.

    1
    2
    
    # Pull nginx latest image from internet
    docker image pull nginx:latest
    
  • Export the image

    1
    
    docker image save nginx:latest -o nginx.tar
    
  • Copy to the airgapped system via scp or via pen drive

    1
    
    scp nginx.tar crucial-system.local:/tmp
    

On Airgapped machine

  • Open terminal and import the container

    1
    
    docker image load -i /tmp/nginx.tar
    
  • Run the container

    1
    
    docker run -d -p 8080:80 --name airgapped-nginx nginx
    

On another machine on same network as Airgapped machine

  • Open terminal and send a curl request to the crucial-system.local

    1
    
    curl http://crucial-system.local:8080/
    
  • Response

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    

Is that enough?

In order to run docker containers you need to install docker on the airgapped system. How would you install that without internet? We may need openssl to generate self signed certificates for the nginx image which we installed. It becomes challenging to install the prerequisite software required to run the application.

IT Admins face many challenges like:

  • Installing prerequisite software.
  • Coping softwares bigger in size will need bigger pendrives or may choke the network.
  • Installing/Upgrading the software.
  • Configuring the software.
  • Debugging the issues with the software
  • Keeping the host machine up to date

Lets see how we can solve few of these issues.

Downloading & Installing docker on airgapped machine

I’ll be using RHEL 9 for this part, these commands can be modified for your linux distro.

  • Open terminal and install dnf-plugins-core. dnf-plugins-core adds download capabilities to the dnf command.

    1
    
    dnf install dnf-plugins-core
    
  • Download docker

    1
    2
    3
    4
    5
    6
    7
    
    mkdir /tmp/docker-rpms && cd /tmp/docker-rpms
    
    # Add Docker Community Edition repo to the package manager
    dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
    
    # Download the latest version of docker along with its dependencies
    dnf download docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin --resolve
    

    The --resolve flag will try to resolve all the other dependencies required by these packages which we have not specified.

  • docker along with its required dependencies will get downloaded in the pwd

    1
    
    ls -l
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    -rw-r--r-- 1 root root    61961 Jul 18 01:20  container-selinux-2.237.0-1.el9_6.noarch.rpm
    -rw-r--r-- 1 root root 34344299 Jul 18 01:20  containerd.io-1.7.27-3.1.el9.aarch64.rpm
    -rw-r--r-- 1 root root 15358454 Jul 18 01:20  docker-buildx-plugin-0.23.0-1.el9.aarch64.rpm
    -rw-r--r-- 1 root root 19052663 Jul 18 01:20  docker-ce-28.1.1-1.el9.aarch64.rpm
    -rw-r--r-- 1 root root  7889252 Jul 18 01:20  docker-ce-cli-28.1.1-1.el9.aarch64.rpm
    -rw-r--r-- 1 root root  3043536 Jul 18 01:20  docker-ce-rootless-extras-28.1.1-1.el9.aarch64.rpm
    -rw-r--r-- 1 root root 13757807 Jul 18 01:20  docker-compose-plugin-2.35.1-1.el9.aarch64.rpm
    -rw-r--r-- 1 root root   197588 Jul 18 01:20  libselinux-utils-3.6-3.el9.aarch64.rpm
    -rw-r--r-- 1 root root    29183 Jul 18 01:20 'passt-selinux-0^20250217.ga1e48a0-9.el9_6.noarch.rpm'
    -rw-r--r-- 1 root root   251813 Jul 18 01:20  policycoreutils-3.6-2.1.el9.aarch64.rpm
    -rw-r--r-- 1 root root    18085 Jul 18 01:20  rpm-plugin-selinux-4.16.1.3-37.el9.aarch64.rpm
    -rw-r--r-- 1 root root    46473 Jul 18 01:20  selinux-policy-38.1.53-5.el9_6.noarch.rpm
    -rw-r--r-- 1 root root  7251875 Jul 18 01:20  selinux-policy-targeted-38.1.53-5.el9_6.noarch.rpm
    
  • Now you can copy the /tmp/docker-rpms directory to a pen drive or to the airgapped machine via scp

    1
    
    scp *.rpm crucial-system.local:/tmp/docker-rpms
    

    Please make sure /tmp/docker-rpms exists on crucial-system.local before you run the scp command.

  • Now we can ssh to the airgapped machine and install docker on it.

    1
    2
    3
    4
    5
    
    ssh root@crucial-system.local
    
    cd /tmp/docker-rpms
    
    dnf install -y *.rpm
    
  • We can verify if docker is installed by running docker --version command on the airgapped system.

    1
    
    docker --version
    
    1
    
    Docker version 28.1.1, build 4eba377
    

    Docker uses a daemon to run and manage containers. We will have to enable docker service before using it.

    1
    
    systemctl enable --now docker
    

Reducing the size of docker image tar archives

The default tar archives provided by docker does not provide best compression when it comes to docker images. We can leverage gzip command to compress the image further.

1
docker image save nginx:latest | gzip > nginx.tar.gz

docker supports gzip, bzip2, xz or zstd archive type for loading the image. Alternatively, you can explore oci-archive format which is supported by most container runtimes.

Conclusion

In this blog we explored various strategies used by software industry to ship their software. So far containers are leading the industry due to the ease of use and isolation provided by them. We saw how IT Admins are shipping docker to their airgapped systems. In next blog we will see what we can do to ease their job.

This post is licensed under CC BY 4.0 by the author.