TLDR - Next in line, I move into Fedora Silverblue, that is an Atomic/immutable Linux version. This is a fancy way to say that it is a “protected” system. Some say it is the future of Linux, others say it is too rigid to be usable. But why is it different? stay tuned and I will try to explain…
1- What is an immutable (linux) distro?
Image1. Fedora Silverblue flavor page.
It is a regular linux system that has one additional “protective” layer on top: The system directories cannot be touched, even by sudo, remember, the superadmin? This means that no program or installation can overwrite system properties.
Even official system updates are applied in a different way… They create a new system “copy”, and apply the updates to this new system copy. What?
Imagine you start your environment…let’s call it “blue”… When you tell it to apply the system updates, a copy of this system is created (green) and the updates are applied in the background over the alternative green system… and only when you restart the computer, you will see a new boot option with the new system, the green, as the default, but also an older blue.
If something goes wrong, brakes the system or a system updates brakes your workflow, you only need to restart the computer and opt for the other system, the blue, that existed before the update was applied.
Is it all sunshine and roses?
No…yes… maybe?
This brings some downsides: remember when you installed applications using the dnf command? You used something like:
dnf group install development-tools
This would expand the existing system, by installing a group of applications, but it would also install libraries, system binaries that are necessary for it to run (these are called the dependencies).
Some of these dependencies would be attached to system directories, so they would be available for other apps to use.
Image2. Error installing apps using regular dnf commands.
When doing regular immutable updates, the atomic updater would not know what to do with these new lines of code. That is why the system directories are protected against writing.
2- So what is the impact of immutability
Basically you loose the ability to install software that needs system access. This guarantees that the system is always stable, not allowing anyone to mess with it.
You get a system more reliable, stable and secure with an amazing roll back capability.
3- How can I install stuff then?
You still have ways to install software in your system, but you will have to rely on different types of packages and install methods (and we already know that Linux has plenty of those ![]()
3.1- System updates.
Use the “Software app” it will do everything for you.
Notice that the button you have is “Restart & Update”. As it is immutable, you will always need a restart to apply system updates.
image3. Updating the Silverblue System
3.2- Flatpaks/appimages/snaps
Instead of installing the app and dependencies on system directories, flatpaks (and the other competing standards that are used in other systems, remember Linux is all about choices) are self contained packages that include all the necessary files and dependencies in themselves.
This means that if one application requires version 1.5 of some library, and another app uses 2.0, they can co-exist in the same Linux system.
But how do they communicate with each other and the rest of the system?
They use a series of “portals”!
If you are used to Android applications, you have witnessed the system asking you what app you want to use to open XYZ content, or what level of permissions you want to give it, and if you give it access to camera or location. (yes, Android is Linux based, and the same idea still applies)
Let me give a simple example.
Image4. Using “Software” application to install Gimp flatpak.
GIMP is a tool for working with images and photos.
Imagine you want to install GIMP as a flatpak. how? By now you know:
Launch the terminal and typ…
…wait… It is almost 2026… frack that!
You launch “Software” app in your GNOME DE and select “GIMP” and press the button that says “Install”.
Congratulations #6 & #7!!! as you just used the equivalent to flatpak install command in terminal line.
You installed a selfcontained (also called sandboxed) app that allows you to work with bitmaps of colors…
But wait! If it is sandboxed how does it access the pictures in my home folder? How do you load an image into it?
As usual!! You select “File>open” from the menu, but then it is not GIMP that navigates on your file directories.
GIMP asks the system portal “what can I use to load one file?”
System offers a set of tools to open/save files… in this case, one: the fileChooser portal.
- Provides the file-open/save dialog (“file picker”) that Flatpak apps use to access files outside their sandbox.
This also implies one cool thing… whatever the programmer of that app used for visual styles, or programming language he chose, you get consistency on the file loading experience.
Whatever the system has, whatever flatpak app is used, the system one is the one that is always used!
So Flatpaks communicate with the rest of your system… and you can check that by using an app like “Flatseal” that lists all the flatpaks installed in your computer, and what permissions they are using. It is very cool stuff that you can control at a very fine level.
image5. Flatseal at work, showing what GIMP is allowed to use
But are flatpaks only available for immutable systems? You can install them on regular systems also. I am from the camp that says you MUST.
They are not perfect, far from it, but who wants perfection when you can have choice?
3.3- Containers
This is the recent “rave” of install method. If you are a newcomer, or a returning old dude like me, you will hit big a container wall. Let me help you pass over it.
3.3.1- Understanding “Virtual”
You have probably heard about Virtual Machines… VMs are “software computers” that live inside the hardware one… meaning when you set one virtual computer up, you will be asked to assign all the “hardware” that the software will have to mimic: You assign the memory quantity, the disc space, and even the number of processor cores that you want your main system to use with it.
It is like you have one Giant transport boat, but you assign some of its engines and space capacity to have another boat inside. Doesn’t seem very logic, and you can’t stack many of them.
#3.3.2- and now containers
Containers are a bit different. A container is, in reality a software box with all contents, features, functions, and apps necessary to perform a task, but that depend on the transporter system to run. So the boat is the same, you just put whatever containers you want on top.
Containers have some other advantages. As they are software containers, you can duplicate them with no effort, remove them, and as they are closed systems, you can be sure that whatever goes inside them, stays inside them (except if you open the doors).
So as a cool kid nowadays, containers are a must to install your developer system, to create your code and to duplicate it… but wait… this means that as they are selfcontained, you can just send them to any one, and when that person runs the container with your code, they behave exactly as it would on your computer.
So, you can create an app, and package it as a container and send it to any server around the world, and it will run exactly as in your computer (as long as it supports containers)
You can even create a “developer system container” with your full tech stack and send it your peers to make sure they have exactly the same setup as you do, even if they are on a mac or windows machine.
3.3.3- Self-contained? That sounded a lot like a flatpak
The inherent idea is the same, but flatpaks are for integration in the desktop system, with a frontend interface that can be developed in any Linux understandable programming language. Containers are a bit more server specific, intended to be used in server technology, and with terminal based commands and a web interface…
But wait… that is what Ruby on Rails is all about!!!
4- Installing ROR as a container.
Luckily Fedora Silverblue already has all the necessary technologies to use containers. It does not come with DOCKER, that is the most known container management toolset, but it comes with a “better” one: Podman.
podman --version
(by now you know what this does!)
Image6. Installed version of Podman in Fedora Silverblue
The commands are exactly the same, the containers are interchangeable, but podman* is a bit more restrict as it does not allow a container to run as Sudo and change system directories. Exactly what we need on an immutable system.
4.1 - How do you get containers installed?
So installing a container has several steps.
4.1.1- Define your starting point
You need to define your starting point, meaning the image that best approaches what you want, and use it as a starting point.
There is already a gazilion images where you can start from. This means that there are repositories where people create images with a pre-configured system setup and upload them for others to use.
If you remember correctly form my previous post, to install Rails you need a system with Ruby, then you install RAILS as GEMs to get the latest rails version.
To find what is available as Ruby Docker images simply type:
podman search ruby
This will list all available base images existing in the authorized repositories (fedora and docker.io) that you can use that have some sort of Ruby
image7. List of all images that are called “ruby”, that you can use as your starting point.
What next?
4.1.2- Define what you want to accomplish
OK, let’s use the default docker.io Ruby image. This garantees that whenever it is officially updated, you also get the updates.
This image is the equivalent of a UBUNTU LINUX with RUBY installed!!
Everything in Linux works based on “written” commands. With Containers, the story is the same.
You start from the image you selected, and then tell the Podman/docker to do stuff with it. As usually depends on a lot of ideas and commands ran in succession, so we need to create a file with all the instructions we want it to follow, to create a new and improved image from the base Ruby… in this case, we need to start from RUBY and tell the system to install RAILS inside the container.
So we need a file with the recipe to go from Ruby to Rails. This file is the magic bit.
Create a folder where you want to store the project you will be developing.
In my case I will be working in the directory `~/Projects/rubyapp1
Instead of the command line, let’s use the “Files” app.
Open the “Files” app. By default it starts on your “Home” directory:
image8. My home directory
You are free to write anywhere into this directory. let’s create a folder with CTRL+SHIFT+N and call it whatever you want. I will be using ~/Projects/rubyapp1/
Start “Text Editor” app and create a new file inside this directory. Call it Dockerfile.rails
Image9. Text Editor (flatpak) app, with the FileChooser portal , selecting where to store a new file that we are editing.
Now put this text inside that file. It includes all the necessary commands to start from a RUBY image and get to an extended image with rails inside:
# Dockerfile.rails
FROM ruby:3.4.7 AS rails-baseinstall
# Default directory
ENV INSTALL_PATH /opt/app
RUN mkdir -p $INSTALL_PATH
# Install rails
RUN gem install rails bundler
WORKDIR /opt/app
# Run a shell
CMD ["/bin/sh"]
The basic Dockerfile commands we used are:
FROM ruby:3.4.7 AS rails-baseinstall
FROM: defines what image to start from. We’ll use the Ruby3.4.7 version image, but from now on treat it as “rails-baseinstall”
ENV INSTALL_PATH /opt/app
ENV: defines environment variables, in this case we define a Environment variable called INSTALL_PATH and give it the value/opt/appwhere “opt” refers to a universal directory where you can install “optional” apps on any linux, and “app”… well because it could be called “bananas”, be it looks more professional if you just go with “app”.
RUN mkdir -p $INSTALL_PATH
RUN: executes commands inside the container. In the example, we use it to create a directory with the same value as defined in the variable $INSTALL_PATH. (in our case it will be /opt/app)
Next, we install RAILS inside this container, notice that this is the gem install command, just like it was being run on your system:
RUN gem install rails bundler
RUN: Next command… use gems to install rails.
WORKDIR /opt/app
WORKDIR: changes the current directory inside the container.
CMD ["/bin/sh"]
Start a SHELL to wait for further commands.
Other usefull docker commands
- ARG: specifies build-time argument variables.
- ENV: defines environment variables.
- USER: changes the active user inside the container.
- CMD: defines the program to run when the container starts.
OK… now we have what we want to accomplish: Start from Ruby official image, set the environment variable for the working directory, install Rails from Gem… and make my user it’s owner. Then go to the working directory and wait for my next command.
4.1.3- Create the new image with Rails
Let’s use the podman build command:
podman build -t rails-baseinstall -f Dockerfile.rails .
podman: Let’s use podman (can be Docker)build: Let’s create a new image…tag or -t: …with the name tag…rails-baseinstall: …name of the image, that you can use in the future to identify this “image” to create containers-f: Using a file as instruction set to operate next…Dockerfile.rails: … that has this name, living inside our active directory.
Lets see it working
First it will ask you what image with Ruby.3.4.7 you want to use… select the last one… the universal image stored in docker.io universal repository.
image10. Some of the choices when pulling an image to start from…
And then follow with the respective “output” obtained from the RUN commands inside.
- Download the ruby.3.4.7 image and store it localy
- define the Env variable and create the directory
- create the user and group
- make the user “Owner” of the directory
- install RAILS from gems command
- Change to the Directory created as workdir
- Start a BAsh session as the final part.
Image 11. Output of the previous podman command, WHEN RAN a second time, as all the downloadables are present in my local disk. If they weren’t there would be a lot more going on on screen with progress bars :).
So… it … nothing in the end… do I have rails installed?
You created an image called “rails-baseimage” with ruby and rails installed. but it is not yet running inside your machine. It is, for now a static image.
You can list all the images you have on your disk by typing
podman images
Image 12. Existing images in local storage. we now have a local copy of Docker Hub Container Image Library | App Containerization image with the version/tag 3.4.7 and we have our own rails-baseinstall “latest” (as we are not working with versioning for sake of simplicity).
But are these …containers?
No…these are images, you can call it “system templates” from where you can start n instances or n copies, or better yet: n containers".
For lack of a better analogy we have now created a specialized crane that can load and unload a specific type of container into your boat.
So this means, that when we need to spool a new “machine” with Ruby on Rails installed w e just need to do podman run to start a new container from the new image…only then you have a running container.
4.1.4- Finally, create a new project using our Rails Container.
Have in mind what we are trying to do here: We now have what you can call a RAILS base image. We can send commands to that image, and each time we do that we are starting (and for now, stopping) a new container.
Note: We didn’t install Ruby or rails in our system… you can check that by asking the system what version you have:
Image13. No versions of Ruby or Rails in my main system.
What we have is a image that can be used to load, on demand, containers that include Ruby and Rails. And we can do pretty much anything with it, as if it would be a Rails installation in your computer, but without “polluting” your system with any development tools.
For instance… let’s create a new Rails Project in my ~/Projects/rubyapp1 directory (move into your own directory):
If Ruby and Rails were installed in my computer, I would have to say in terminal:
rails new <name_of_my_project>
That would create a new folder with a new project using Rails.
So we need to pass a similar command to the container using podman run and some more information:
podman run -it --rm -v "$PWD:/opt/app:Z" rails-baseinstall rails new homebudget
podman: hey, podman…run: … do the following:-it:(But hey, attach what you are doing to this shell session, so it stays within this shell session (we don’t want ghost processes running after we finish))…--rm: … and don’t forget to wipe any changes done to our container during the process…-v "$PWD:/opt/app:Z": … (This one is tricky but it is the most important part) and whatever you do inside the container, on this directory (/opt/app), replicate it to my local shell, so I also get the files here in my computer… That weird “:Z” is there because of an extra security feature in Fedora that is SELINUX that adds additional tags in files, to better manage permissions… This makes the files the container creates owned by the active user, and not the “root” user… wich is great for security.rails-baseinstall: … do this using the image we created before…rails new homebudget: … create the project homebudget using rails.
image14. A container is created, and inside it the
rails new command is ran, creating a new folder structure for a new application. As we also asked podman to write them into our main linux folder structure we now have also a new directory called /homebudget in our home/projects/rubyapp1/ directory:
Image 15. “homebudget” rails new project is created in our main linux home directory.
5- Review and conclusion
Here is what we have been up to…
- We started by using Silverblue as an immutable Linux distro to be sure we don’t install any software at system level that can contribute to “instability”, and continued to see what types of install you can use in it.
- We talked briefly about “packaged” apps in flapaks and how they interact with your system
- We moved to Basic Container world
- We created a “rails-baseinstall” toolkit image with basic ruby and rails install inside
- We run the image to temporarily create a container and used it to create a new Ruby on Rails application directory on the base system.
That is a lot.
Next up, I wil be looking into optimizing all this to Podman and Silverblue (the user conundrum was badly explained and allows for a tldr kind of post on its own).
…and I just wanted to create a HTML application.
Jpcarvalhinho














