Setting up remote containers for IAC dev environments in dotnet 6 with postgres and SMTP
2022-04-20
In this post I will go through how to set up remote containers for a dotnet 6 API project using PostgreSQL and an SMTP server, so that any new devs picking up the project only have to clone down the git repo and open it in Visual Studio code to get started debugging it.
No dependencies need to be installed onto developer machines for each project they work on, other than:
- Docker
- Visual Studio Code
Yes, that's all they need. They don't even need to install any extensions - the only one they need will be prompted the first time they open the project in vscode. Any extensions they need for the project will be loaded in a vscode server instance within the docker container, and then their local vscode will allow access to the vscode server as if they're using it natively, right down to providing terminal access within the container.
How to set up the project
You will need to ensure that you've created a .gitattributes
file in the root folder if you don't have one already, and specified * text=auto eol=lf
to default all the line endings to LF, if you're on Windows and find that swapping between the host and the container changes the line endings in all your files. Alternatively, if you're already using Windows line endings, use crlf
instead of lf
.
In the root of the repo create a folder called .devcontainer
. Within this you need to create three files:
devcontainer.json
docker-compose.yml
Dockerfile
devcontainer.json
This is customised from the default Microsoft file. You can change the name, the vscode settings (although if you're working with newer dotnet projects I'd recommend leaving omnisharp.useModernNet
set to true
), add any extensions you want to use in vscode for this project (find the ID for an extension by installing it in your local vscode, then right clicking it and clicking Copy Extension ID
- I've included some of my favourites for aspdotnet projects but the only one you need is ms-dotnettools.csharp
), the post-create commands and the remote user.
There is an issue where Omnisharp, the underlying technology in the C# vscode plugin doesn't work properly unless dotnet restore
is run at the point of setting up the dev container, so do not remove that command.
docker-compose.yml
The docker compose file sets up the three components of this example project:
- The dotnet 6 API
- The PostgreSQL database
- The SMTP server
Take note of the name of the SMTP server container as this will be needed later, as will the environment variables for the database. These should be changed from postgres
.
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
# Update 'VARIANT' to pick a version of .NET: 3.1, 5.0, 6.0
VARIANT: "6.0"
# Optional version of Node.js
NODE_VERSION: "lts/*"
volumes:
- ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:db
# Uncomment the next line to use a non-root user for all processes.
# user: vscode
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
db:
image: postgres:14.1
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: postgres
# Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
mail:
image: bytemark/smtp
restart: unless-stopped
volumes:
postgres-data:
Dockerfile
This comes directly from Microsoft, I've made no modifications to it.
# [Choice] .NET version: 6.0, 5.0, 3.1, 6.0-bullseye, 5.0-bullseye, 3.1-bullseye, 6.0-focal, 5.0-focal, 3.1-focal
ARG VARIANT="6.0"
FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
appsettings.json
and appsettings.Development.json
To get the SMTP working, use these keys. If you're doing anything more fancy with bytemark/smtp
than just the default functionality you may need to change the SMTP port.
To connect to the Postgres database set your connection string to "User ID=postgres;Password=postgres;Host=db;Port=5432;Database=postgres;Pooling=true;"
, substituting in your chosen username, password and database name.