Patching is relatively easy to solve with immutable infrastructure. Build a new fully patched AMI every night and when you release you pick (version of code, version of AMI) to deploy.
Deploying new code: publish a new container, scale up green, switch, whack blue at your leisure.
Patching: publish a new AMI, scale up green, switch, whack blue at your leisure.
1. Every night we build a new freshly patched Ubuntu image.
2. Three times a week we run a deploy that rebuilds our entire infrastructure in place with the latest Ubuntu image as the base [1].
3. Once the deploy runs we never run apt install or apt update again.
So rather than
server.update()
we do server = server.update()
[1] This sounds fancy but I promise it's stupid simple, all the complexity is in the auto scaling groups and the load balancers which we don't manage. And it's the exact same procedure to do code deploys which we do multiple times a day.