Skip to content

Blog

Free up space used by Docker

Docker can consume a significant amount of disk space over time. Here are some tips to reclaim disk space used by Docker:

  1. Remove unused containers: powershell docker container prune

  2. Remove unused images: powershell docker image prune

  3. Remove unused volumes: powershell docker volume prune

  4. Remove unused networks: powershell docker network prune

  5. Remove all unused data: powershell docker system prune

By regularly cleaning up unused Docker resources, you can free up valuable disk space.

Once the above is done, you can optimise the space used by the Docker VHD by running the following commands in an elevated PowerShell prompt:

# Stop the Docker service
docker desktop stop

# Optimize the Docker VHD
Optimize-VHD -Path C:\Users\<YourName>\AppData\Local\Docker\wsl\disk\docker_data.vhdx -Mode full

# Start the Docker service
docker desktop start

Obviously, replace <YourName> with your actual Windows username.

Start Aspire dashboard locally

Running the Aspire dashboard locally and independent of Aspire can be useful. Instructions are available in the official documentation.

The following command will run the Aspire dashboard in a Docker container, mapping ports 18888 and 4317 on the host to the container. The --restart always option ensures that the container will automatically restart if it stops or if the Docker daemon is restarted. --env ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true sets the dashboard to run in open mode, removing the need to enter a token each time.

docker run --restart always -it -p 18888:18888 -p 4317:18889 --env ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true -d --name aspire-dashboard mcr.microsoft.com/dotnet/aspire-dashboard:9.4

Once running, you can access the dashboard at http://localhost:18888.

Outlook logging into Office 365 Error

If you get an error 4usqa / 3399614475 when trying to log in to Office 365 from Outlook (desktop or mobile) all of a sudden as especially if it's multiple users, try the following:

  1. Go to the Entra home page: https://entra.microsoft.com/
  2. Sign in as a tenant admin
  3. Search for Microsoft Information Protection API
  4. Go to "Properties"
  5. Select Yes for "Enabled for users to sign in?"

The solution was found on this Microsoft answers page.

Teeth Straightening

Back in 2023, I dedcided to get my teeth straighened. I did this for a couple of reasons:

  1. Let's be honest, it looks better!
  2. Straighter, non-overlapping teeth are easier to clean and maintain, which makes my life easier and helps keep the dentist bills down!

A few friends had recently been going through the process and were using Invisalign and, given my dentist was a provider, I decided to go with them too.

The process was as follows:

  1. Initial consultation with the dentist to discuss the process and get prices
  2. Initial scan of my teeth to create a 3D model and show a simulation of the potential end result (this cost about £350)
  3. A few weeks later, I had a follow-up appointment to discuss the simulation and decide if I wanted to proceed, which I obviously did - total cost was about £4,000
  4. I had an initial 29 week run and then a subsequent 14 week run with the option of more phases if I wanted to do some more "tweaking"
  5. You then wear the retainers for a further few months to help the teeth settle into their new positions before switching to only wearing them at night
  6. As part of the "package", you also get an included whitening treatment which you do once you get the retainers

The results

Before

Before

Week 2

This was taken shortly after starting, i.e. when the attachments were first attaching to my teeth. This photo shows the bottom tooth's overlapping more too.

Week 2

After

After

Pros and Cons

Pros

  • Once you sign up, you don't pay any more - i.e. you're not paying for one round of aligners, you're paying for the whole process, however many rounds that takes
  • You can take them out to eat, drink and clean your teeth, which is a lot easier than braces
  • They are far less visible than braces - most people didn't even notice I was wearing them

Cons

  • Retainers are a just the same as the aligners - due to the extremely tight fit, the lower aligner from my first set broke due to plastic fatigue of taking them out
  • Replacement retainers - sold as a pack of 3 pairs - are about £350, which is a lot for basically hitting print on a printer!
  • At week 15 of the initial set of aligners, I raised concerns that certain teeth hadn't moved as expected (i.e. based on the aligners I was wearing) but the decision was made to continue until the end of the set, rather than adjusting the aligners
  • This decision is probably the only reason the extra 14 weeks were needed as the only thing really being "fixed" in that second set were the two teeth I'd pointed out at week 15

Conclusion

I am very pleased with the overall result but a review and refinement half way though would improve the process. Also, reducing the cost of replacement retainers would be a good idea too, even if it means same price but more than 3 pairs.

CI & CD

This article is a summary of my understanding and use of Continuous Integration, Continuous Delivery and Continuous Deployment. There are several interpretations of these terms, some of which I'd argue are more correct than others. My interpretation is based on my experience and the processes I've followed and also articles by companies like AWS and by experts in the field like Dave Farley.

Continuous Integration

I always use a trunk-based approach, whether that be when building software, pipelines or Infrastructure as Code (IaC). I usually use short-lived feature branches rather than committing directly to the main branch, especially when working with others. I never use long-running branches, opting for feature toggles to manage the rollout of new features.

I then typically use pull requests to:

  • Verify the changes are the ones I intended
  • Run automated tests
  • Get feedback from others

Once the pull request is approved, I merge it into the main branch, usually using a squash commit. This triggers a build pipeline that will also run automated tests but it also builds packages, containers, etc... Once the build is successful, the deployment phase(s) of the pipeline begin.

Continuous Delivery

Every successful commit to main not only triggers the build process but also the deployment phase(s) of the pipeline, ultimately pushing code all the way to production.

Regardless of how many environments I have in place, the process tends to be the same for them all:

  • If environment is subject to change management, raise a change request
  • Deploy the change to the environment - if code:
    • Database changes first
    • Code changes second
  • Run automated tests (these may vary between environments)
  • If no automated tests exist, show a manual approval gate
  • Close the change as successful or failed as appropriate

If a deployment fails, sometimes excluding the development environment, then all changes are automatically reverted. This is to get the environment back to a known good state as quickly as possible.

Continuous Deployment

Continuous deployment is effectively the same as continuous deliver but with any manual gates removed. When building pipelines, I typically build them all to support continuous deployment but, when automated testing isn't available, revert to using a manual approval gate.

I'd say the biggest barrier to going to continuous deployment is the lack of automated testing or at least a lack of trust in your automated testing. If you can't trust your tests to catch issues, you can't trust your deployment to be successful. Once you have highly reliable and high confidence (and ideally high speed) automated testing in place, you can move to continuous deployment with confidence.

Delete a tag in ACR repository using CLI

If you have a tag in an ACR repository that you no longer need, you can delete it using the Azure CLI. It's a simple process and just requires remembering a few property names.

If you've not logged into Azure, do that first:

az login

Then, list the repositories in the registry to find the tag you want to delete:

az acr repository list --name acrname

Next list the tags for the repository you're interested in:

az acr repository show-tags --name acrname --repository your.repository

Once you've found the repository and tag you want to delete, you can delete it:

az acr repository delete --name acrname --image your.repository:1.2.3-alpha.456789

Obviously you'll need to replace acrname, your.repository and your.repository:1.2.3-alpha.456789 with your own values.

Output variables in PowerShell and GitHub Actions

When running a PowerShell script within a GitHub Actions workflow, you may wish to output variables from one step and access them in another.

Below is a simple example of outputting a variable in one step and accessing it in another:

name: Pass value from one step to another
on: 
  workflow_dispatch:
  push:
    branches:
      - main

jobs:
  PassTheParcel:
    runs-on: ubuntu-latest
    steps:
    - name: Determine some values
      id: calculate_values
      shell: pwsh
      run: |
        $ErrorActionPreference = "Stop" # not required but I always include it so errors don't get missed

        # Normally these would be calculated rather than just hard-coded strings
        $someValue = "Hello, World!"
        $anotherValue = "Goodbye, World!"

        # Outputting for diagnostic purposes - don't do this with sensitive data!
        Write-Host "Some value: $someValue"
        Write-Host "Another value: $anotherValue"

        "SOME_VALUE=$someValue" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
        "ANOTHER_VALUE=$anotherValue" | Out-File -FilePath $env:GITHUB_OUTPUT -Append

    - name: Use the values
      shell: pwsh
      env: 
        VALUE_TO_USE_1: ${{ steps.calculate_values.outputs.SOME_VALUE }}
        VALUE_TO_USE_2: ${{ steps.calculate_values.outputs.ANOTHER_VALUE }}
      run: |
        $ErrorActionPreference = "Stop" # not required but I always include it so errors don't get missed

        Write-Host "Values received were `"$($env:VALUE_TO_USE_1)`" and `"$($env:VALUE_TO_USE_2)`""

Whilst both examples use PowerShell, there is no requirement that both steps use the same shell.

Adding an additional route to a VPN connection in Windows 11

If you're running a split VPN in Windows 11 (i.e. one which sends only certain traffic over the VPN and does not use the VPN as the default gateway), you may wish to add specific IP addresses to also be routed over the VPN. An example of this might be a service which is only accessible via a certain IP address.

Assuming you've already set up your VPN connection in Windows, you can add a route using the following PowerShell command:

Add-VpnConnectionRoute -Name '<Split VPN Name>' -DestinationPrefix <123.45.67.89>/32

Where:

  • <Split VPN Name> is the name of the VPN connection you wish to add the route to
  • <123.45.67.89> is the IP address you wish to route over the VPN rather than via your default gateway/normal internet connection

For example, if you have a VPN connection named My VPN and you wish to route traffic to 216.58.204.68 over the VPN, you would use the following command:

Add-VpnConnectionRoute -Name 'My VPN' -DestinationPrefix 216.58.204.68/32

The Journey That Is My Career

I’ve worked as an IT professional for over 20 years having been fortunate enough to have been around computers from a young age and then going on to study Software Engineer at university. In those 20+ years, I’ve had several different roles in a few areas of IT at several companies. This article is about the journey. If you want to see “the facts”, that’s what my LinkedIn profile is for!

What’s This About?

This article is a summary of my career and why I’ve made the choices I’ve made. A lot of the choices made along the way weren’t right or wrong necessarily but, with hindsight, I’m not sure I’d make the same choice if I knew then what I know now. Having said that, I’m happy with where my life is right now but the “best advice” to my past self may not match the decision I (didn’t) make at the time.

Take what you will from this article, whether that be a way to waste a few minutes or something to learn from or, dare I say it, inspire you to take the next step in your career path.

First “Proper” Job

My first “proper” job was actually my placement year at university. I count this as a proper job as it was one year, full time and doing similar jobs to the rest of the IT staff at the company.

The year was split into three parts – six months in the support department, five months in one of the dev teams and a further six weeks in the support department, partly covering for the manager who was on leave. Despite really wanting to be a software engineer, developer or whatever term you want to use, it turned out the part of the year I’d really enjoyed was working in the support team. The year also gave me a lust to get into the working world after completing my degree.

Post-Graduation

After my experience during my placement year and approached the end of my final year, I started applying for several IT support positions around the country and ended up being offered two positions – one in Leeds and one in Abingdon, Oxfordshire. In the end, I opted for the latter as it was slightly more money, in the Thames Valley corridor and, as I knew people in the area already from my placement year, had a pre-established social life and more living options via house shares. The actual jobs were similar enough that, from my perspective at the time, it didn’t make too much difference at such an early stage in my career.

I started my new role in early September 2001, a very memorable time in most people’s lives, regardless of how close you were to the events of the 9/11 attacks. Like many, I remember where I was when I first heard about it and struggled to keep up-to-date with the still relatively new internet news and adding servers took weeks or months, not minutes.

After being in my new role for a few months, I started doing some coding again, working on a support system for internal use and also managing things like annual leave between performing my other duties.

All was going well until July 2001 when we all told the company was going into administration and, effective immediately, we all had no jobs and my short tenure meant no redundancy either. Needless to say, I began job hunting immediately. This wasn’t the easiest time as I was competing with a whole year’s worth of graduating IT students.

Take 2…

In the following couple of months, the company had been bought out and downsized but taken on some of the old staff. I was then asked to come in and do some contracting work which, after a little while, was converted into a full time role, effectively just picking up where I left off.

Once again, all was going well until February 2003 when the new company went into administration but this time it wasn’t coming back.

Take 3…

As the old company was wrapping up, I was contacted by the old managing director of the initial version of the company stating he was putting together a bid to be the assets and clients and would like me to join the new team. I liked the work, I liked the people, the salary was acceptable and, honestly, it meant no need to job hunt so I accepted the offer.

All was going well for a few years, I got a nice (nothing crazy) pay rise and we even started working on a new version of the product using C# and the .NET Framework. It was then that the problems started…

Warning Signs!

Salary payments weren’t always being paid on time and, even if it was just a few days, that makes you worry when you have mortgage payments to make (yes, I was able to buy when I was young thanks to buying with a friend but that’s another story!) and I didn’t have a pile of cash lying around to cover the shortcomings.

Over the next couple of years – yes, years! – things got worse and worse with salary payments now being several months behind. I “stayed loyal” to this company for a long time as it continued to owe me more and more money and whilst I did look at and even interview at a couple of places, ultimately I lacked the C# experience many places were looking for as I think we were only in the early months of development at this point and all the learning was self taught. This was in a time before all the excellent tutorials sites like Pluralsight were mainstream and YouTube offerings were limited to mainly cat videos.

I did realise enough was enough in early 2008 and began looking for a new opportunity, eventually finding a role at a company I’d interviewed at a year previous but didn’t have the necessary C# experience.

By the time I left “take 3”, they owed me four months salary! Fortunately, for me, the company went into administration shortly after I said I was leaving so the government compensation scheme kicked in and covered about half of the amount owed.

The Long Journey Begins

My next position ended up being a nearly fourteen year tenure in various roles within the IT department.

I started out as a developer, working on a mix of classic ASP and .NET products and was doing this for about six months when the development manager changed (I won’t go into the details about why) resulting in me getting a new line manager. For various reasons, this new setup wasn’t working for me so I began looking for new roles, along with other colleagues in the department.

Two weeks later, the new development manager resigned unexpectedly and I was approached by the dev manager’s manager about taking on some of the technical parts of their role, specifically around the database and server management. I agreed to this as I like to have a broad understanding of how the systems are setup that the software is running on.

Over the course of the next couple of years, I got on with my work, helping out the team, working on planning, supporting recruitment, etc… then in 2011 I took on the role of a team leader. Management wasn’t my goal at the time but I was effectively doing several parts of the role anyway and, as you’d expect, it included a pay rise so I accepted the offer.

More Management

In the latter half of 2016, the decision was made by senior management to offshore a lot of the development team to India, mainly for cost reasons, resulting in several redundancies in my team. I was offered a newly created role of Software Engineering Manager with day-to-day management of the entire UK part of the development team that was remaining as well as general management of the whole development team.

This role would see me pushed towards a more managerial and less hands-on position which, even at the time, I wasn’t massively keen on or looking for. I think that, partly due to the safely blanket my current company offered and partly as it was a promotion (which is a good thing, right?!), I accepted once again.

I then spent two years in this position, dealing with the running of the development team and managing the processes we followed as well providing hands-on support to the team when needed. Due to another reshuffle, I was given direct management of the entire development team and another new line manager; my seventh since joining the company.

Is this the right path?

By this point, in early 2019, I was becoming concerned about where my career was heading as I still wanted to be doing a significant amount of hands-on work but I was spending an increasing amount of time in meetings, etc… doing things that didn’t really feel were a good use of my time or skills. There were definitely a good few of these meetings I felt fell into the category of “this could have been an email” as they were largely conveying decisions, regardless of whether it was presented as a discussion or not.

One thing the department, and specifically my manager, had been discussing was the use of cloud hosting, instead of the current bare-metal setup and the technologies and flexibilities that would open up. This discussion, especially combined with the enthusiasm from my manager at the time, pushed me to spend a lot of my own time looking into containerisation, including Kubernetes, as well as brushing up my development skills to help take the development team into the “brave new world” that the cloud offers as we were still almost exclusively developing in .NET Framework. I was also thinking, at the same time, this will be good for my CV although this wasn’t my only motivation and I certainly didn’t have “one foot out of the door”.

Is This What I Want?

By late 2019/early 2020, I was giving serious thought to moving on to another company but I knew I needed to get my skills up to scratch and, at this point, I was thinking of going into a duel management/hands-on role. What I was sure of at this point was my current role was useful to my current employer but wasn’t making me a good candidate for the wider job market and was therefore stunting my career. For this reason, I set myself a few goals:

  • Get Kubernetes up and running with a real production workload
  • Improve the logging being used within the team
  • Get the dev team practices updated to the standards common in the industry
  • Get application deployments, especially in Kubernetes, as smooth as possible to help “sell” the new way of working
  • Give the development team members a sense of ownership of a product from design and coding to deployment to production

Whilst there was some resistance along the way, particular regarding unit testing and pull requests (yes, these weren’t really being done which now scares me with hindsight!), standards were improved and Kubernetes was progressing with some applications migrating over to the new platform in 2021.

Time To Go!

Over the summer of 2021, my manager, who had also been a big supporter of the work I’d been doing with Kubernetes, decided to leave, leaving a void in the company structure but it also meant seeing a vital ally to the “new way” going. This had me asking questions like could I do their job, could I get their job or do I even want their job? After a few weeks without an update, I pushed for one from management and was told they were rejigging things again and not planning on having a direct replacement.

These changes resulted in a few conclusions/realisations for me:

  • My (management) career within the company had stalled with no realistic path forward without others leaving
  • My salary was rapidly approaching the ceiling for my grade and having seen an, on average, below inflation rise over the past few years was, in real terms, falling
  • Progression in a technical role wasn’t really possible after a certain level – a level I’d already passed
  • My role, due to team structure changes, had been devalued in my opinion with a key part of the development process moved into another team

It was at this point I decided I had to go – I was “piggy in the middle” with reduced autonomy and job satisfaction had dwindled significantly, some overnight but some steadily over the previous year or two. A subsequent change a few months later further devalued my role although, in that case, I do believe this change was a good choice for the affected sub team’s efficiency, it just didn’t help me.

I actually wondered, given how my role was changed, if management were trying to phase out my role (and me therefore!) after a current long running project completed, scheduled for mid-2022 although realistically it would be sometime in 2023. Whilst I never had any confirmation of this, it does illustrate how I felt my position at the company was.

I began applying for roles that were either hands-on or, at least, mainly hands-on. I was looking at both software engineer roles and DevOps engineer roles. After several months of searching, I found a role I liked so I handed in my three months’ notice and began doing a lot of handover meetings and padding out the detailed documentation I’d already written.

Three months later and my (almost) fourteen year tenure was over. Whilst I enjoyed the hands-on part of my role, the other parts were increasingly demotivating and so I was pleased to be going.

A (Brief) New Beginning

The role I’d accepted was doing software development, mainly using TypeScript/JavaScript centred around React and Express, both of which were new to me. There was some .NET Framework-based C# in the mix with plans for a key admin system being built in .NET 6/7 as well as moving their microservice hosting over to Kubernetes.

All was going well, I loved the team I was working with and was enjoying the work enough until the main C# work and/or Kubernetes work started but then opportunity came knocking and the new employer was no longer certain of going down the Kubernetes path.

In mid-September 2022, I was contacted by an agency with a few roles that were DevOps engineer roles in my preferred technologies of C#, Azure and Kubernetes. I was in my probationary period still (i.e. short notice period) and decided it was an opportunity I couldn’t pass up so I accepted one of the new roles and two weeks later I was gone.

And Here We Are…

I started my current role in early October 2022 and I’ve been loving it. The tech stack is the perfect fit, the team I’m working with have been very helpful and the big new Kubernetes project that’s coming up should be very interesting and challenging and I can’t wait to get my hands on it!

2024 Update

It’s now December 2024 and several things have changed at my current employer. I’ve had two changes of role following the departure of my team lead and other department reorganisations. My main project also started – R&D in December 2022 and proper in May 2023. This saw the first client-facing infrastructure going out in Q2 of 2024.

The size of the technology team at the company is much larger than previous employers I’ve worked for (approximately 100 people) so several key functions such as "DevOps" (pipelines, etc…) and infrastructure are covered by different teams. This does lead to a narrower area of work that is often the case with a DevOps role. Fortunately the project did allow me to in both of these areas as the company moves to greater use of IaC and Terraform.

Whilst I’ve gained the exposure to Azure and Terraform that I’d been looking for in switching roles (twice!), I've not always had the same sense of ownership I’ve been used to - bigger pond and all that - but the state of play is an evolving one and hopefully 2025 will see greater ownership. Something I didn't think I’d be saying is that, at times, I am missing some of the physical interactions of being in the office. Unfortunately my current office is 1½ - 2 hours away so it’s not time or cost efficient to go in more regularly. I do try to make sure that some of those casual chats are still happening, albeit via Teams during catch ups with my direct reports.

Final Thoughts

Your career is just that, your career. Whilst people may help you out along the way and see your potential, they will likely only see things from the perspective of what you can offer them or the company. This may not be the best thing for you thought so, for example, if you’re being pushed up the management chain, make sure that’s what you want.

Is there a perfect job? I’m not sure but I think there a few things that you ideally want:

  • Acceptable compensation (salary, leave, pension, etc…)
  • Working conditions (remote/hybrid/office working, flexible hours, part time, etc…)
  • A supportive team that you can rely on – this applies regardless of whether you are the junior or the manager
  • Work that keeps you challenged and interested

I think that if you look at what you do, it’s worth thinking “would this look good on my CV?” and that’s not because it’s “all about you” but because it can be a good indication if you should be doing something. If your company is still coding exclusively in .NET Framework, you aren’t going to have as much choice compared to .NET 6/7/8 coders, especially as time goes on. There’s legacy support of course, but these legacy systems will eventually go.

I integrated the technologies I wanted on my CV into my role as I had the ability to do so and I had the support of my manager. Why did I have that support? It was a good set of skills for the company to have, as well as me, and that is a good sign you’re on the right path.

I’d also recommend going to things like Meet Ups and seeing what the “real world” uses and even how many jokes are being made at the expense of the technologies you and your company are still using.

Whatever your motivation for looking for a new job – money, flexibility, technology, people or even just bored and demotivated – look at what you have and look at what you need and the market wants and don’t be afraid of that challenge to build up your skills to get the career you want. Leaving a company, especially after a long time, can be big and scary thing but once you do, taking that next step is much easier.

Delete a Kubernetes resource that is stuck "Terminating"

General Resource

Run the following command to force a resource to delete. It works by removing all finalizers. Only use this if a resource has become “stuck”.

kubectl patch resourcetype resource-name -n resource-namespace -p '{"metadata":{"finalizers":[]}}' --type=merge

Replace resourcetype with the type of resource (e.g. pod, helmrelease, etc…), replace resource-name with the name of your resource and resource-namespace with the name of the resource which the resource belongs to.

If the resource has become orphaned (i.e. the namespace a resource belongs to has been deleted), recreate the namespace and then run the above command for each resource.

Namespace

If a namespace is stuck and the above method doesn’t work, run the following command, replacing my-namespace with the name of your namespace to delete.

kubectl get ns my-namespace -o json | jq '.spec.finalizers = []' | kubectl replace --raw "/api/v1/namespaces/my-namespace/finalize" -f -

Solution found on Stack Overflow.