Flexible Development Environment Using Docker
Published on April 22, 2024For us software developers, especially in enterprise setup, it’s crucial to create a dedicated development environment to manage multiple projects with different dependencies as easy and efficient as possible.
In this post, I want to share how I setup my development environment from scratch, and in every Operating System I use.
Operating System
Everything starts on which Operating System are we using. In my opinion, Ubuntu is the best operating system for software development. But since I also do gaming, my personal machine uses Windows, and I just use Windows Subsystem for Linux (WSL) for my development projects.
If you are using WSL, I prefer to use the Debian
distro instead of the
default Ubuntu
distro, because the Debian
distro doesn’t have any
pre-installed packages, so you’re basically starting from scratch, which is
what we want.
Basic Ubuntu Packages
Now that we have an OS to work with, let’s just install some basic packages we need in development.
Open up your terminal and update our package manager.
Then install our packages.
What did we install?
git
: For version control and managing repositories.zsh
: I preferzsh
over Ubuntu’s defaultbash
shell.curl
andwget
: For fetching remote files/endpoints. Most libraries out there uses them for installation.unzip
: For extractingzip
files.make
: Some libraries usesmake
for installation. We can also use it to simplify workflow by creating aMakefile
for some projects.
Terminal
Default Login Shell
Since we’ve installed zsh
, let’s use it for our login shell.
This command will change the default shell from /usr/bin/bash
to /usr/bin/zsh
. It will ask for your password so just type it there.
After changing the login shell, restart your terminal completely to apply the changes.
Warp
I’ve recently discovered this terminal emulator on the internet, and it looks very good. Warp is a terminal application that has a lot of features that makes our life way easier. It has a smart autocompletion, IDE-like keybindings, very intuitive and customizable UI, heck, it even has integration with AI if you want to ask something about commands or anything. Its latest major release includes Linux support, though Windows support is still in development (there is a workaround where you can run Warp in WSL, though it’s not officially stable: Link Here).
Installation
- Go to the Warp website.
- Download the
.deb
file. - Copy the filename of the downloaded file (including
.deb
). - Open up your terminal and install the app using
apt
:
While Warp is a great terminal app to use, its main caveat for most users is that you need to sign up for an account in order to use it. Which is quite weird for just a terminal application. But if you don’t mind it like me, then we’re good to go!
After successful installation and sign up, you can now configure your Warp depending on what works the best for you. But for me, here are some settings I have that want to share:
- Features > Editor
- Open completions menu as you type =
true
- Expand aliases as you type =
true
- Show input hint text =
true
- Tab key behaviour =
Accept Autosuggestion
- I like to use
tab
to accept autocomplete, and Warp now assignsctrl + space
to open completion menu. Which is like using Copilot in VSCode. I like that.
- I like to use
- Open completions menu as you type =
Tools
Next, we can install tools we need for development projects. Tools like Node.js
, Bun
, PHP
, Rust
or any other command line tools you may need for specific projects. You can just search the internet on how to install such tools in your OS. I’m gonna leave that task to you!
Even if we’re gonna use Docker for our dev environment, I think it’s fine to install these tools in our machine for generating a project, for example.
Code Editor / IDE
I don’t wanna make a debate on what Code Editor or IDE is the best, let’s just use the most accessible and easier to use, Microsoft VSCode. Since we’re on Ubuntu, we have a lot of ways to install VSCode on our machine, either using snap
, flatpak
, etc. But for this one, I think we should just directly download the .deb
package from the VSCode website itself.
- Open your browser and go to the VSCode website.
- Download the
.deb
file. - Copy the filename of the downloaded file (including
.deb
). - Open up your terminal and install the app using
apt
:
Docker
I know, I know. At first, Docker is very overwhelming to use. But just bear with me, because I’m gonna walk you through all commands you need to know and how to use Docker on your projects. It’s also a great skillset to have as a software developer.
Why Docker?
There are a lot of blog posts and YouTube videos on why and how Docker solves a lot of common problems in software development. But in my opinion, the main reason I like to use Docker is that I can just easily run all my projects at the same time without interrupting my host machine, especially if my projects have different dependencies. For example, I have these projects:
- a backend written in Node.js v21 with MySQL 5.7,
- an API written in PHP 8.1,
- a React app running in Node.js v18,
- a Laravel app running in PHP 8.3 with MySQL 8.0, with a frontend running in Node.js v20.
You can easily notice the differences in PHP and Node.js versions for every project. If I just install every dependencies in my host machine, man, it’s a pain-in-the-ass managing different versions, and most of the time it will have a conflict on something like ports. Docker makes it easy to isolate projects with their corresponding dependencies ready to spin up everytime.
Let’s start with installing Docker Engine.
As much as I love Docker Desktop, sometimes there are some weirdness on the Docker Engine included in it, especially in Ubuntu. So if you are in Ubuntu, I recommend to just install the Docker Engine with the CLI to interact with it.
After the commands succeed, you can sanity-check if Docker is really installed.
If both commands doesn’t have any errors, congratulations! You just installed Docker! But there’s one more crucial step we need to do so we can use Docker even without root privileges (without prefixing docker commands with sudo
).
This command will add your user to the docker
group, and we need to
restart our system for the changes to apply.
After restarting our system, we should be able to use Docker without root privileges. Let’s test it out!
This command will pull the hello-world
image from Docker Hub and try to run it. This should have an output of something like:
Nice! We now have Docker working in our system. Onto the next step!
Global Docker Services
Now, installing Docker won’t instantly spin up services we need for our development environment, it’s just a tool for us to easily run multiple services using compose.yaml
files. So we need to have a global compose file to have services we’ll use on every project we have.
What global services do we need?
Well, in my dev environment setup, I like to have these services globally:
Traefik
An easy-to-use reverse proxy for our services. I like to have one especially if I have to manage different projects and give it a unique domain I can use to access the app. I don’t even need to think of a unique port to expose for each project (It’s tiring bruh).
DbGate
This is actually optional. You can use whatever database client you’re most used to. But DbGate is just the best I’ve tried so far. It’s free, fully-featured, supports all types of databases (SQL, NoSQL), and the best part, we don’t even need to install it as a standalone application in our system! It has an official Docker Image that we can use to run the service locally on the web.
Let’s install them all!
Before we create our global services configuration, let’s first create a user-defined Docker network which we will use on all our services, so that all of them will connect on a single network:
Then, create a compose.yaml
file on our home directory and open it up in VSCode:
Create the traefik
service:
Wow. This is kinda overwhelming to understand but basically, it just pulls the official Traefik v2.11 image from Docker Hub and we configure it how we want. After this configuration, you don’t even need to touch this unless you want to customize more. You can just refer to their Documentation to learn more.
Now for our dbgate
service:
As you may notice, we declare a volume
on the dbgate
service, so we need to include a top-level volumes
configuration for that:
We also need to define the Docker network we used on our services:
And.. that’s it! Here’s our full compose.yaml
Time to run the services
Alrighty! Let’s spin ‘em all up!
What does this command do?
docker
: communicate with the Docker Enginecompose
: use the Compose plugin by Dockerup
: run the services declared on thecompose.yaml
file-d
: run in detached mode (in the background)
It should take a while to pull and build the containers. Probably around 5-10 minutes, depending on your computer and internet speed. Once the build is complete, you should see a success message like this:
You should be able to access the services using their custom domains!
traefik
: http://traefik.localhostdbgate
: http://dbgate.localhost
Conclusion
That’s basically it. Now you have a flexible dev environment setup using Docker! To test things out, check out my other posts to setup different frameworks using this setup. Happy coding!