diff --git a/.vscode/settings.json b/.vscode/settings.json index 9fa4553..9c1d44a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "cSpell.words": ["Actix", "Gandi"] -} \ No newline at end of file + "cSpell.words": ["Actix", "Gandi"], + "cSpell.enabled": true, + "cSpell.enableFiletypes": ["markdown"] +} diff --git a/content/img/devcontainer-debian-example.png b/content/img/devcontainer-debian-example.png new file mode 100644 index 0000000..382f50b --- /dev/null +++ b/content/img/devcontainer-debian-example.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f956c04f18968350598589511350a9b16c83ddd6ef73f902572c71efda30634 +size 11155 diff --git a/content/posts/2022.02.10.why-use-devcontainer.md b/content/posts/2022.02.10.why-use-devcontainer.md new file mode 100644 index 0000000..b9a261a --- /dev/null +++ b/content/posts/2022.02.10.why-use-devcontainer.md @@ -0,0 +1,161 @@ +--- +title: "Why I use Dev containers for most of my projects" +date: 2023-02-09T23:14:05-05:00 +toc: false +images: +tags: + - dev +--- + +It is important to have a consistent and streamlined setup process for your +development environment. This saves time and minimizes frustration, both making +you more productive and also making it much easier to onboard new developers. +This is important, whether we're talking about a company who wants to onboard +new engineers or an open source project that needs more contributors, being able +to press one button to get a fully functional development environment is +incredibly valuable. + +That's why I was thrilled when I discovered dev containers! Dev containers use +containers to automate the setup of your development environment. You can have +it install compilers, tools, and more. Set up a specific version of nodejs, +install AWS cli, or run a bash script to run a code generator. Anything you need +to set up your development environment. And you can also run services like +databases or message queues along with your development environment because it +has support for Docker compose. + +For example, I use dev containers to spin up Redis and CouchDB instances for a +project I'm working on. It also installs pnpm, then uses it to install all the +dependencies for the codebase. The end result is that you can press one button +to have a fully functional development environment in under a minute. + +This has many advantages. It ensures that everyone has the same version of any +services or tools needed, and isolates these tools from the base system. And if +you ship your code with containers, it also makes your development environment +very similar to your production environment. No more "well it works on my +machine" issues! + +## Basic setup + +I use dev containers with VSCode. It has pretty good support. I've also tried +the [dev container CLI](https://github.com/devcontainers/cli) which works fine +if you just want to keep everything in the CLI (although you could probably +stick with docker compose alone then!). + +VSCode comes with commands to automatically generate a dev container +configuration for you by answering a few questions. + +![A VSCode prompt window. "deb" is typed into the prompt, and the text "Simple debian container with git installed" is highlighted below.](/img/devcontainer-debian-example.png) + +At the core of dev containers, what sets it apart from just using Docker is the +"features". These are pre-made recipes that install some tool or set up some +dependency within your dev container. There is a lot of these available, +installing everything from `pnpm` to `wget`. You can also set up commands to run +when the container is created --or even every time the container is started-- to +install or set up anything else that features didn't cover. + +```json +{ + // ... + "features": { + "ghcr.io/devcontainers/features/node:1": {}, + "ghcr.io/devcontainers-contrib/features/pnpm:2": {} + }, + "updateContentCommand": "pnpm install", + // ... +} +``` + +Above is an excerpt from the dev container of a project I'm working on. I needed nodejs and pnpm, +and I then use pnpm to install the dependencies. + +## Docker compose + +But I honestly probably would not have used dev containers if this was all they +did. What I find even more impressive is that they can be set up to use docker +compose to bring up other services like I mentioned at the beginning. + +To do that, you create your docker compose file with all the services you need, +but also add in the dev container. + +```yml +version: '3.8' +services: + devcontainer: + image: mcr.microsoft.com/devcontainers/base:bullseye + volumes: + - ..:/workspaces/my-project:cached + command: sleep infinity + environment: + - COUCHDB=http://test:test@couchdb:5984 + - S3=http://minio:9000 + + couchdb: + restart: unless-stopped + image: couchdb:3.3 + volumes: + - couchdb-data:/opt/couchdb/data + environment: + - COUCHDB_USER=test + - COUCHDB_PASSWORD=test + + minio: + restart: unless-stopped + image: minio/minio + volumes: + - minio-data:/data + command: server /data --console-address ":9001" + +volumes: + couchdb-data: + minio-data: +``` + +In the example above, I'm setting up a CouchDB database and Minio S3-compatible +store. Docker gives containers access to each other using the container names. I +pass the endpoint URLs as environment variables to my dev container, where I can +read and use them. + +Then, you just tell your dev container config to use the docker compose file. + +```json +{ + "name": "my-project", + "dockerComposeFile": "docker-compose.yml", + "service": "devcontainer", + "workspaceFolder": "/workspaces/my-project", + + // Adding the Rust compiler, plus the AWS cli so I can access the S3 API of minio from the CLI. + "features": { + "ghcr.io/devcontainers/features/rust:1": {}, + "ghcr.io/devcontainers/features/aws-cli:1": {} + }, + + // The project I'm working on exposes the port 8080. + // I forward that out so I can look at it on my browser. + "forwardPorts": [8080], + + // Set up the development AWS config and credentials with test values, + "onCreateCommand": "mkdir -p ~/.aws/ && /bin/echo -e '[default]\nregion = local' > ~/.aws/config && /bin/echo -e '[default]\naws_access_key_id = minioadmin\naws_secret_access_key = minioadmin' > ~/.aws/credentials", + + // Create the S3 bucket + "postCreateCommand": "aws s3 --endpoint-url $S3_ENDPOINT mb s3://my-bucket", + + // I found that I have to add this, but it's not the default. Not sure why. + "remoteUser": "root", + + "customizations": { + // You can even add in VSCode extensions that everyone working on the project + // would need, without them having to install it on their own setup manually. + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "streetsidesoftware.code-spell-checker" + ] + } + } +} + +``` + +That's it! Run the "Dev Containers: Reopen in Container" command in VSCode, give +it a few minutes, and you'll have your full development environment ready.