I spent four years in IT support, resetting passwords, imaging laptops, and patiently explaining to vice presidents that their email was not broken, they were just offline. I was good at it, and it paid the bills, but I felt like I was watching the real engineering work happen on the other side of a glass wall. I wanted to be the one building the systems, not just resetting them. DevOps seemed like the bridge: close enough to operations that my experience mattered, deep enough in engineering that I could finally write code for a living. But every job posting required experience I did not have, with tools I had only read about. So I gave myself a challenge: build one real, working project that proved I could do the job, and use it to get hired. This is exactly what I built, how it fell apart and came back together, and what it taught me about breaking into a career that felt just out of reach.
The Moment I Realized IT Support Was a Dead End for Me
I was on a late shift when a monitoring alert woke up the on-call engineer. I watched him SSH into a server, run a few commands, and fix the issue in under two minutes. He was calm, efficient, and completely unimpressed by the crisis that had paged him. I thought, “I want that.” Not just the skill, but the relationship to the systems. I wanted to be the one who understood them deeply enough to fix them under pressure, not the one who handed off the ticket and waited. That night, I started looking at DevOps job descriptions. They all mentioned Linux, cloud platforms, CI/CD, infrastructure as code, and monitoring. I knew Linux from tinkering with a home server. The rest were words I recognized but could not claim competence in. I needed a way to turn those words into a story I could tell in an interview.
Designing the Project That Would Prove Something
I decided to build a fully automated deployment pipeline for a simple web application. The app itself was not the point. It was a small todo list API built with Node.js and Express, with a React frontend. The point was everything around it: infrastructure defined as code, a CI/CD pipeline that built and tested the code on every commit, a cloud environment that auto-scaled, and monitoring that would actually wake someone up if things went wrong. I set a scope that felt ambitious but achievable: a working production deployment that I could show during an interview, with a link to a GitHub repository that demonstrated I understood the tools.
I chose AWS because it was the most common in job postings. I chose Terraform for infrastructure as code because it was cloud-agnostic and I wanted to learn a skill that transferred. I chose GitHub Actions for CI/CD because it was free for public repos and integrated with the code I was already writing. I chose Docker because it seemed like the universal packaging format. I chose Prometheus and Grafana for monitoring because they were open source and widely used. The stack was ambitious for someone who had never written a Terraform file, but I was about to learn by doing, and by failing repeatedly.
The First Failure: Terraform and the State File Confusion
I started with Terraform. I opened the AWS console, created an IAM user with admin permissions (a bad practice I would later fix), and configured the AWS CLI on my laptop. Then I wrote a simple Terraform file to create an S3 bucket for storing the application’s static assets. It did not work. The error was about the state file, a concept I had not bothered to understand. Terraform had created a local state file on my laptop, and when I tried to run it again from a different directory, the state was out of sync. I deleted the state file manually, which caused Terraform to lose track of the bucket it had created, and I had to manually delete it from the console. I learned the hard way that Terraform state is the single source of truth, and losing it is like losing the map to your own infrastructure. I reconfigured the project to use a remote state backend in an S3 bucket with DynamoDB locking, which I later understood was a best practice. That mistake cost me an evening, but it burned the concept of remote state into my brain.
Networking: The VPC Trap
The next hurdle was networking. I needed a VPC with public and private subnets, a NAT gateway, and an internet gateway. I had heard these terms but never configured them. I wrote a Terraform module that created the VPC and subnets, only to find that the instances in the private subnets could not reach the internet to download packages. I had forgotten the NAT gateway. I added it, but then the NAT gateway itself needed to be in a public subnet with a route to the internet gateway. I spent two evenings drawing boxes on paper, tracing the paths, and finally understanding how packets flow. That paper drawing session was more valuable than any tutorial. When it finally worked, I could ping an instance in a private subnet, through a NAT gateway, to the internet, and I felt like I had unlocked a secret level of cloud engineering.
Docker and the Multi-Stage Build Revelation
With the infrastructure taking shape, I Dockerized the application. I wrote a Dockerfile for the Node.js backend that started from a Node slim image, copied the source, installed dependencies, and exposed the port. It was straightforward. The React frontend was trickier. I needed to build the static files and then serve them with nginx. I initially used two separate Dockerfiles: one for the build step and one for the nginx server. Then I discovered multi-stage builds: a single Dockerfile that uses one base image to build the React app, and another to serve it. The final image was tiny, under 50 megabytes. The efficiency felt elegant. I learned to love the FROM and COPY --from=build syntax. I also learned to keep secrets out of Dockerfiles by using build arguments that were not hardcoded. All of this was new territory, and every small success felt like a promotion from within.
CI/CD and the Test That Failed Me
With Docker working locally, I set up GitHub Actions. The goal was to run automated tests on every push, build the Docker images if tests passed, push them to Amazon ECR, and then trigger a deployment to ECS. I wrote a workflow YAML file from scratch, using the marketplace actions for AWS and Docker. The first push failed because I had hardcoded a secret in the code (the Stripe test key) and the test tried to call Stripe’s API, which timed out in CI. I learned to use environment variables and GitHub Secrets. The second push failed because I had not set up the ECR repository yet, so the image push step had nowhere to go. I added Terraform to create the ECR repository and the ECS cluster, and then I realized I had to coordinate the order of operations. I ended up with a separate Terraform run for infrastructure before the CI/CD pipeline could deploy. This was the messy reality of DevOps: tools are not isolated, they overlap, and the glue between them is where most of the work lives.
The Interview That Changed Everything
After two months of evenings and weekends, I had a working deployment. The todo app was live at a real domain, secured with HTTPS via AWS Certificate Manager, fronted by an Application Load Balancer, running on ECS Fargate with auto-scaling, and monitored by Prometheus and Grafana dashboards that showed request rates, error rates, and latency. The GitHub repo had a clean README with architecture diagrams, a link to the live site, and a detailed explanation of every tool and decision. I was proud of it, but I was also terrified to show it to anyone. Then I applied to a junior DevOps role at a mid-sized startup. In the cover letter, I included a link to the repo and a brief explanation of what I had built. I did not expect a callback. I got one.
The interview was a video call with two senior engineers. They asked about my support background, but quickly pivoted to the project. I shared my screen and walked them through the Terraform modules, the CI/CD pipeline, and the monitoring setup. When they asked why I chose Fargate over ECS on EC2, I explained the tradeoffs around management overhead and cost, referencing my experience with a failed EC2 launch configuration that I had debugged. When they asked about state management, I described the night I deleted the Terraform state file and what I had learned. They laughed. I got an offer the next day. The project had not just demonstrated technical skills. It had shown I could learn, fail, and recover without giving up. That was the real thing they were hiring for.
What I Learned About Career Transitions
The transition from IT support to DevOps was not about certificates or bootcamps. It was about building a single, credible artifact that proved I could operate in a cloud-native environment. The project was not perfect. I am sure there were security misconfigurations I missed, and the monitoring was shallow. But it was real, and it was running, and that mattered more than being flawless. The experience also taught me that DevOps is not just about tools. It is about mindset: the willingness to automate, to treat infrastructure as code, and to own the whole lifecycle from commit to production. That mindset was what the interviewers were probing for, not my memorization of kubectl commands.
I also learned that my IT support background was not a weakness. It was my superpower. I understood users, I understood the pain of bad deployments, and I understood the consequences of downtime in a visceral way that pure developers sometimes missed. I brought a respect for stability and monitoring that came from years of cleaning up after broken releases. In the DevOps role, that perspective was valued, not dismissed.
What I Would Do Differently
Looking back, there are a few changes I would make to the project that would have made it stronger and my learning faster. I would have started with a simpler cloud provider, like a single DigitalOcean droplet, before going to AWS. The VPC and networking complexity consumed weeks that could have been spent on the application and monitoring. The fundamentals of CI/CD and Docker are cloud-agnostic, and a simpler environment would have kept the focus on those. I would also have added more failure injection: intentionally breaking the database connection, exhausting disk space, and seeing how the system reacted. The project was a happy path deployment, and real production engineering is about the unhappy paths. Finally, I would have documented the journey publicly as I went. A blog or a series of tweets about the struggles would have built a network and demonstrated communication skills, which are critical in DevOps. My project was strong, but it was silent. In a field that values transparency and knowledge sharing, that was a missed opportunity.
Advice for Anyone Making a Similar Jump
If you are in IT support or another non-development role and dreaming of DevOps, build something that you can show. It does not need to be original. It needs to be running, with real DNS, real TLS certificates, and real monitoring. Focus on the plumbing: the pipeline from code commit to live traffic. Write infrastructure as code from day one, even if it is messy. Let yourself fail in public, or at least in a place where an interviewer can see the evolution of your commits. The project will become your resume, and it will speak louder than any list of certifications.
Remember that the ability to learn is the most important skill in this field. The tools will change, but the pattern of encountering an unknown system, researching it, trying something, failing, and recovering is eternal. My Terraform state file disaster was not a disqualification. It was the story that got me the job. Your disasters, owned and learned from, can do the same. The gap between IT support and DevOps is not as wide as it looks. It is bridged by a single project, a few late nights, and the courage to apply before you feel ready.
