When running multiple SQL Server containers on a Docker host we should always be setting CPU and Memory limits for each container (see the flags for memory and cpus here). This helps prevent the whole noisy neighbour situation, where one container takes all the host’s resources and staves the other containers.
But what if we forget to set those limits? Well, no worries…we can update them on the fly!
Let’s have a look. First let’s run a container with no memory limits: –
docker container run -d --publish 15789:1433 --env ACCEPT_EULA=Y --env MSSQL_SA_PASSWORD=Testing1122 --name sqlcontainer1 mcr.microsoft.com/mssql/server:2019-CU12-ubuntu-18.04
Confirm the container is up and running: –
docker container ls
Now have a look at the stats of the container: –
docker stats
This container is running on a host with 4GB of RAM so pretty much no limit in place. Let’s add a limit: –
docker update sqlcontainer1 --memory 2048MB
N.B. – Thanks to Anthony Nocentino (b|t) for pointing this out to me, I was under the (wrong) impression that limits couldn’t be changed on a running container…so this is really cool.
In fact, if you want a better explanation on container limits I recommend you check out Anthony’s post Container Limits and SQL Server
Anyhoo, now let’s have a look at the limits in place: –
docker stats
Cool! So we’ve set a limit for our running container!
BUT! What if we know how those limits are enforced…can we enforce a limit on a running container without using docker update?
Let’s have a go! First remove the existing container and re-deploy: –
docker container rm sqlcontainer1 -f docker container run -d --publish 15789:1433 --env ACCEPT_EULA=Y --env MSSQL_SA_PASSWORD=Testing1122 --name sqlcontainer1 mcr.microsoft.com/mssql/server:2019-CU12-ubuntu-18.04
Confirm, no limit in place: –
docker stats
Same as before.
Right, limits on containers are enforced by control groups (cgroups)…when processes are placed in cgroups those cgroups (for memory, cpu etc.) limit the amount of the host’s resources that a process can use.
And that’s all containers really are…just processes running on the host.
So let’s find the cgroup for the memory limit for the container.
First grab the container ID (have to set the limit as root so switching here): –
sudo su CONTAINERID=$(docker ps -aq) && echo $CONTAINERID
Then have a look at the memory control group
find /sys/fs/cgroup/ -name *$CONTAINERID* MEMORYCGROUP=$(find /sys/fs/cgroup/ -name *$CONTAINERID* | grep memory) && echo $MEMORYCGROUP ls $MEMORYCGROUP cat $MEMORYCGROUP/memory.limit_in_bytes
So no limit in place. Let’s set a limit and confirm: –
echo 2147483648 > $MEMORYCGROUP/memory.limit_in_bytes cat $MEMORYCGROUP/memory.limit_in_bytes
Looks good, now let’s check docker stats: –
docker stats
And there’s the limit in place! Kinda cool…working out how Docker is placing resource limits on containers by using cgroups. If you fancy reading more about how container works, check out my SQL Containers From Scratch blog here.
Thanks for reading!