It's easy to configure a couple of servers manually. But it would be a nightmare to do that with hundreds or thousands of servers. That's why we have tools like Puppet.
Puppet can automatically configure any number of systems. We just need to declare the state we desire for those systems. And we do that with the help of Puppet DSL (Domain-Specific Language), also sometimes called "Puppet code".
Some languages are procedural, but Puppet code is declarative. In a procedural language, we describe "steps that need to be followed" to get to a final state. In declarative languages, we just specify the final state we desire. Otherwise said, we don't tell Puppet how to get to that final state. It figures out all the necessary steps on its own.
What's so cool about this? Well imagine we need an identical final state for 2 systems. But system1 and system2 are currently in two different states. A procedural approach would take the same steps on both systems, which may lead to inconsistent results. But Puppet, due to its declarative nature, can intelligently adapt. It will notice these two systems are configured differently. So it will take one set of actions on system1, and a different set of actions on system2. In the end, both system1 and system2 will be in an identical final state.
Check out this easy-to-understand course if you want to learn more about how Puppet works.
How does Puppet work?
Puppet uses a server-agent architecture.
The Puppet playground will provide you with all the necessary prerequisites to run Puppet code.
If you are an absolute beginner in Puppet, KodeKloud provides a Puppet course to help you understand the basics.