One of my favorite features in Azure DevOps is the Service Container, which allows spinning up infrastructure dependencies for build process as Docker containers. They are also available in GitHub Actions, which comes as no surprise since Microsoft runs both those shows. GitHub provides some great tutorials for PostgreSQL and Redis Service Containers, but recently when needing to run Microsoft SQL Server we ran into some hiccups, so I thought I’d share what ended up working.
⚠ If you’re not familiar with GitHub actions or want more info about Service Containers, peep the linked documentation above, they do a much better job explaining than I might.
We’ll dive right into using SQL Server. Let’s start with a dead-simple build that is using a PowerShell script to compile and run automated tests that use a Database.
name: Test for PRs on: pull_request: workflow_dispatch: jobs: run-tests: runs-on: ubuntu-latest steps: - name: Compile and Test from Build Script shell: pwsh run: .\build.ps1 ci-pr $
Adding Service Container
Believe it or not, MS SQL Server is available as a Linux container on DockerHub, which is pretty incredible in the grand scheme of history. There are versions for both 2017 and 2019, and while there is an option to set the license for production use, the option defaults to the free
Developer edition, which is exactly what we need for use on our Continuous Integration agent.
We can plug the image we want as Service Container in our workflow definition:
name: Test for PRs # omitted, see above jobs: run-tests: runs-on: ubuntu-latest services: mssql: image: mcr.microsoft.com/mssql/server:2019-latest env: SA_PASSWORD: MyTestPassword ACCEPT_EULA: 'Y' ports: - 1433:1433 steps: # omitted, see above
SA_PASSWORD environment variables are required to run, the latter of which is relevant to our app. Even though the password is just for test, it can’t hurt to save it as a Secret for the repository, in which case we would replace the value above with
Configuring Tests to Use the Container
Now that our build is spinning up that database as a Service Container, we’ll need to make sure our tests know how to connect to it. If you’re working with MS SQL Server, it’s likely your connection string is authenticating “the easy way” with local-trusted Windows
Trusted_Connection=True. That’s not going to fly on Linux, and we need will need to use a username/password connection string, with the container’s automatic
sa and the password we used above.
We’ll pass in the connection string for the Service Container as an environment variable to the step we run our tests on:
# omitted, see above steps: - name: Compile and Test from Build Script shell: pwsh run: .\build.ps1 ci-pr $ env: ConnectionStrings__MyConnString: "Server=localhost,1433;Initial Catalog=MyTestDb;User Id=sa;Password=MyTestPassword;"
Again, it’s a good practice to save any password as a Secret, in which case you’d use
For the tests to use this new value, we need to include environment variables in our app’s configuration. Assuming you’re in .NET and using Hosting extensions and the default
Host.CreateDefaultBuilder(), your config will include them automatically. Otherwise you’ll need to add the
Microsoft.Extensions.Configuration.EnvironmentVariables NuGet package, and add it to your Configuration buildup:
var configuration = new ConfigurationBuilder() //other providers like appsettings.json .AddEnvironmentVariables() .Build();
And that’s it! Our tests will use that environment variable for the Connection String, and connect to our Service Container database when they run. When the job is complete, GitHub Actions will tear down the container, so don’t use this for anything that requires persistent data between runs. Docker is a slick fit for infrastructure and dependencies during development (and in production), so it’s nice we can use them in our build environment as well!