\u003C/figure>\n\u003C!-- /wp:image -->\n\n\u003C!-- wp:heading -->\n\n\u003Ch2 id=\"phase-1-lab-testing-all-the-things\">Phase 1: Lab Testing…All The Things\u003C/h2>\n\n\u003C!-- /wp:heading -->\n\n\u003C!-- wp:paragraph -->\nI’m incredibly lucky to have a lab environment to play with. At the start of this project, I had two lab Windows Server Failover Clusters (\u003Ca href=\"https://docs.microsoft.com/en-us/windows-server/failover-clustering/failover-clustering-overview\">WSFC\u003C/a>) - each with 2 nodes that were running Windows Server 2016, SQL Server 2017. Each cluster had availability groups (AG), as well as a distributed availability group (DAG) between the two clusters. Since I didn’t want to destroy these clusters for the test, I needed to create new servers for testing.\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\nMy goal was to replicate our production set-up on a much smaller scale. From there, I’d work through different scenarios to get to the final desired result. The 2012 production clusters looked like this:\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:image -->\n\u003Cfigure class=\"wp-block-image\">\u003Cimg src=\"https://www.tarynpivots.com/image/2019/2012cluster.jpg\" alt=\"Stack Overflow Windows 2012 Clusters\"/>\u003C/figure>\n\u003C!-- /wp:image -->\n\n\u003C!-- wp:paragraph -->\nProduction had two WSFCs running Windows Server 2012, each with 3 nodes. Both clusters have at least one availability group, as well as one distributed availability group going to a reporting cluster. Once this project was complete, the new clusters would look the same, however, these would have a new OS, new cluster names, and when finished, the primary SQL Server in each availability group would be the current NY Secondary.\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\nIn order to properly test, I needed 3 servers running Windows Server 2012. Well, guess what? We didn’t even have a way to install Windows Server 2012, and no longer had an image of the software. This left me hunting for a copy of it. Eventually I got one, but then our deployment process needed to be setup to work with 7 year old software. Once all those bits were in place, I was able to \u003Ca href=\"https://twitter.com/tarynpivots/status/1083158959937093632\">spin up my 3 servers to test with\u003C/a>. At this point, I had a new 2012 cluster with 3 nodes (2 in NY, 1 in CO). All were running SQL Server 2017 with 2 availability groups, with one AG that was limited to this cluster, and a second AG that was modeled after one in a distributed availability group.\u003Cbr>\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph {\"align\":\"center\"} -->\n\n\u003Cp style=\"text-align:center\">\u003Ca href=\"https://stackoverflow.com/jobs?utm_source=so-owned&utm_medium=blog&utm_campaign=jobs2019&utm_content=headhunters\">\u003Cimg class=\"wp-image-11745\" style=\"width: 500px;\" src=\"https://stackoverflow.blog/wp-content/uploads/2017/05/Ad-5-Sidebar@2x-2-copy.png\" alt=\"\">\u003C/a>\u003Cbr>\u003Cbr>\u003Cbr>\u003C/p>\n\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\n\u003Ch3 id=\"the-will-this-even-work-test\">The \"Will This Even Work\" Test\u003Cbr>\u003C/h3>\n\n\u003C!-- /wp:heading -->\n\n\u003C!-- wp:paragraph -->\nBefore I started breaking this new test cluster, we had the idea of creating another server with Windows Server 2019 to see if it would work with the new lab cluster - basically, a test to see if the data would sync. I spun up another new server; this time it was on a fancy new operating system, Windows Server 2019, with SQL Server 2017 and was all ready to start testing. The goal was to insert the 2019 server into the mix with 2012, so it would receive data from the old server cluster. I wanted it to look like this:\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:image -->\n\u003Cfigure class=\"wp-block-image\">\u003Cimg src=\"https://www.tarynpivots.com/image/2019/Lab2012Cluster_2019.png\" alt=\"Lab Cluster - single 2019 server\"/>\u003C/figure>\n\u003C!-- /wp:image -->\n\n\u003C!-- wp:paragraph -->\nI tried many things to get this to work. I even tried things I knew wouldn’t work just to cross it off the list of things tested. Here’s a brief list of some of the things I tried:\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:list -->\n\n\u003Cul>\u003Cli>Putting the 2019 server into the existing 2012 cluster - as expected, this fails due to the operating systems being different.\u003C/li>\u003Cli>Attempting to add it to the existing AGs when not being in a cluster - this fails because it’s not in a cluster.\u003C/li>\u003Cli>Creating a separate single node cluster for the 2019 server and attempted to add as a replica to the AG. This failed as well.\u003Cbr>\u003Cbr>\u003C/li>\u003C/ul>\n\n\u003C!-- /wp:list -->\n\n\u003C!-- wp:paragraph -->\n\u003Ca href=\"https://twitter.com/tarynpivots/status/1088158572486090752\">None of these things worked.\u003C/a> I was beginning to wonder how we were going to do this. My next test was to create a new distributed availability group for each existing availability group, using that as a way to insert the 2019 server into the mix. I finally hit on something that worked for the single server. After creating a new DAG between the 2012 and 2019 cluster, I had data syncing between two clusters on different operating systems. I was ecstatic to get this to work with one server, but how would I do this with the 3 servers in a single cluster, with all the AGs and distributed AGs already in play?\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:heading -->\n\n\u003Ch2>The Mock-up Production Test\u003Cbr>\u003C/h2>\n\n\u003C!-- /wp:heading -->\n\n\u003C!-- wp:paragraph -->\nOnce I knew I could have clusters with different operating systems, synchronizing data via distributed AGs, I needed to attempt this with the new 2012 lab cluster. Since it was already working as a stand-alone cluster with SQL Server running, I wanted to set up a test that was as close as possible to what we have in production. I needed a replica of our reporting cluster. A bell went off in my head, ‘Ding! Ding!’ I had an existing 2016 cluster in my original lab environment - that would be perfect in this case.\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\nMy plan of attack for this test was to first setup a DAG between the 2012 cluster and the original lab cluster running on 2016. This would be similar to what we had in production at the time. Basically we’d have the following:\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:image -->\n\u003Cfigure class=\"wp-block-image\">\u003Cimg src=\"https://www.tarynpivots.com/image/2019/Lab2012_2016Cluster.png\" alt=\"Lab Cluster - 2012 to 2016\"/>\u003C/figure>\n\u003C!-- /wp:image -->\n\n\u003C!-- wp:paragraph -->\nWhen that was setup and synchronizing, I had a decent, albeit, small version of our production setup. It was now time to start breaking things. My thinking was to start with the NY secondary server and perform the following steps:\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:list {\"ordered\":true} -->\n\n\u003Col>\u003Cli>Evict it from the existing 2012 cluster\u003C/li>\u003Cli>Rebuild it with the Windows Server 2019\u003C/li>\u003Cli>Create a new WSFC with one node\u003C/li>\u003Cli>Install SQL Server 2017\u003C/li>\u003Cli>Finally, create new distributed AGs from the old cluster to the new one to sync the databases with that AG\u003Cbr>\u003Cbr>\u003C/li>\u003C/ol>\n\n\u003C!-- /wp:list -->\n\n\u003C!-- wp:paragraph -->\nMy next step was to do the same thing with the CO secondary in the 2012 cluster. The difference being, it could just be added as a node to the new WSFC, and as a replica to the AGs in the new cluster. At this point in the process, I’d have the old 2012 cluster with a single server sending data to two clusters - the mocked up 2016 reporting cluster and the new 2019 cluster. Visually it’d look like this:\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:image -->\n\u003Cfigure class=\"wp-block-image\">\u003Cimg src=\"https://www.tarynpivots.com/image/2019/Lab2012_2016_2019cluster.png\" alt=\"Lab Cluster - 2012 to 2016 and 2019\"/>\u003C/figure>\n\u003C!-- /wp:image -->\n\n\u003C!-- wp:paragraph -->\nBefore upgrading the last 2012 server, I would need to perform a failover of the distributed AGs from the 2012 cluster to the new 2019 cluster. In looking at this, there was one glaring problem…the reporting cluster. If I performed a failover of the distributed AGs to the new 2019 cluster, the reporting cluster would stop getting data. I saw there were two options:\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:list {\"ordered\":true} -->\n\n\u003Col>\u003Cli>Perform the failover and let the reporting cluster fall out of sync until I could get it everything back in place\u003C/li>\u003Cli>Move the reporting cluster and it’s distributed AGs to the receive data before I failed over to the new 2019 cluster and “hope” things just starting syncing again.\u003Cbr>\u003Cbr>\u003C/li>\u003C/ol>\n\n\u003C!-- /wp:list -->\n\n\u003C!-- wp:paragraph -->\nEither way, the databases on the reporting cluster were going to fall out of sync, so I chose the first option for the lab.\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\nNow that the decision was made, it was easy peasy to finish the move in the lab. There was only one server left in the old cluster, so my steps were to failover the distributed AGs to the new 2019 cluster (yes, I tested failing back just in case), destroy the 2012 cluster, rebuild the server with Windows 2019, add it to the 2019 WSFC, install SQL Server, and add it as a replica to all the AGs. Yay, everything was done! What’s left was just a bit of clean up of the reporting cluster distributed AGs, and then I was ready to move to production with the plan.\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\nI spent the next week writing up all the steps to move to production. There were a lot of moving pieces for production. I had to move the following:\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:list -->\n\n\u003Cul>\u003Cli>2 WSFC\u003C/li>\u003Cli>6 servers with new OS, fresh SQL Server installs\u003C/li>\u003Cli>5 availability groups with a total of about 385 databases\u003C/li>\u003Cli>5 AGs means 5 temporary distributed AGs to help with the move\u003Cbr>\u003Cbr>\u003C/li>\u003C/ul>\n\n\u003C!-- /wp:list -->\n\n\u003C!-- wp:paragraph -->\nThis also meant we needed new IP addresses for the clusters, AG listeners, as well as new names for the clusters, AGs, distributed AGs, and listeners. During my testing, I discovered that you can’t use the same names for these objects, even when they’re on different servers, which resulted in a lot of legwork to get prepped for the move to production, but I was ready…or so I thought.\u003Cbr>\u003Cbr>\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:heading -->\n\n\u003Ch2 id=\"phase-2-the-part-where-i-broke-dev\">Phase 2: The Part Where I Broke Dev\u003Cbr>\u003C/h2>\n\n\u003C!-- /wp:heading -->\n\n\u003C!-- wp:paragraph -->\nTo read the rest of this post, head over to \u003Ca href=\"https://www.tarynpivots.com/post/how-stack-overflow-upgraded-from-windows-2012/#phase-2-the-part-where-i-broke-dev\">Taryn's blog\u003C/a>.\n\u003C!-- /wp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cbr>\n\u003C!-- /wp:paragraph -->","html","2019-07-22T13:54:35.000Z",{"current":440},"how-stack-overflow-upgraded-from-windows-server-2012",[442,450,455,460,464,468,473,478],{"_createdAt":443,"_id":444,"_rev":445,"_type":446,"_updatedAt":443,"slug":447,"title":449},"2023-05-23T16:43:21Z","wp-tagcat-bulletin","9HpbCsT2tq0xwozQfkc4ih","blogTag",{"current":448},"bulletin","Bulletin",{"_createdAt":443,"_id":451,"_rev":445,"_type":446,"_updatedAt":443,"slug":452,"title":454},"wp-tagcat-engineering",{"current":453},"engineering","Engineering",{"_createdAt":443,"_id":456,"_rev":445,"_type":446,"_updatedAt":443,"slug":457,"title":459},"wp-tagcat-serverfault-com",{"current":458},"serverfault-com","Serverfault.com",{"_createdAt":443,"_id":461,"_rev":445,"_type":446,"_updatedAt":443,"slug":462,"title":463},"wp-tagcat-servers",{"current":463},"servers",{"_createdAt":443,"_id":465,"_rev":445,"_type":446,"_updatedAt":443,"slug":466,"title":467},"wp-tagcat-sql",{"current":467},"sql",{"_createdAt":443,"_id":469,"_rev":445,"_type":446,"_updatedAt":443,"slug":470,"title":472},"wp-tagcat-stackoverflow",{"current":471},"stackoverflow","Stackoverflow",{"_createdAt":443,"_id":474,"_rev":445,"_type":446,"_updatedAt":443,"slug":475,"title":477},"wp-tagcat-superuser-com",{"current":476},"superuser-com","Superuser.com",{"_createdAt":443,"_id":479,"_rev":445,"_type":446,"_updatedAt":443,"slug":480,"title":481},"wp-tagcat-windows",{"current":481},"windows","How Stack Overflow upgraded from Windows Server 2012",[484,490,496,502],{"_id":485,"publishedAt":486,"slug":487,"sponsored":12,"title":489},"65472515-0b62-40d1-8b79-a62bdd2f508a","2025-08-25T16:00:00.000Z",{"_type":10,"current":488},"making-continuous-learning-work-at-work","Making continuous learning work at work",{"_id":491,"publishedAt":492,"slug":493,"sponsored":12,"title":495},"1b0bdf8c-5558-4631-80ca-40cb8e54b571","2025-08-21T14:00:25.054Z",{"_type":10,"current":494},"research-roadmap-update-august-2025","Research roadmap update, August 2025",{"_id":497,"publishedAt":498,"slug":499,"sponsored":12,"title":501},"5ff6f77f-c459-4080-b0fa-4091583af1ac","2025-08-20T14:00:00.000Z",{"_type":10,"current":500},"documents-the-architect-s-programming-language","Documents: The architect’s programming language",{"_id":16,"publishedAt":17,"slug":503,"sponsored":12,"title":20},{"_type":10,"current":19},{"count":505,"lastTimestamp":506},24,"2023-05-25T09:46:48Z",["Reactive",508],{"$sarticleModal":434},["Set"],["ShallowReactive",511],{"sanity-t8QG5TU-M8lMtswn0dPNavy2SfKWwMQcggjPK-MyMAo":-1,"sanity-comment-wp-post-11658-1756201623999":-1},"/2019/07/22/how-stack-overflow-upgraded-from-windows-server-2012/?cb=1"]