My personal theory of modern software development is that the #1 and #2 things you can to do improve software quality are:

1) Make sure devs can run a realistic version of the whole stack locally.

2) Drive incremental build times and effort on the whole stack to zero.

With today's world of frameworks, dependencies, and microservices it's too hard to just "think through" a change. You need to try it, adjust, and try it again. Reducing friction on the iteration cycle makes this task pleasant and increases the likelihood of discovering the best solution. When this cycle is painful devs are likely to stop at the first working solution (or even partially working).

I find 1) especially challenging with microservices. What technologies do you use/recommend to help with this?

This is where a Docker/K8s containerised setup can help.

Not trivial to get to, but for deve/test environments it can be really beneficial. Can also mean the same clean starting point for every series of tests, if new containers are spun up each time through.

how do you combine this approach with some external services (i.e. databases aren't run in docker but AWS RDS or some part of the setup is using AWS lambdas)?

https://github.com/localstack/localstack

Is a pretty good testing framework that we use at my workplace for a dockerized microservice setup. Requires some config but has mocks for most of the big services (specifically RDS looks to be in their paid tier, but we get along w/ the free version just fine.)