This is fundamentally not how Puppet (and most configuration management frameworks) are designed to be used.
A good way of remembering it is that the intention of a declarative language is to declare the state you wish the system to be in. The declaration should be the "single source of truth" and is equivalent of saying "I want all cars that are built by this assembly line to be red, have four doors and four wheels".
With that in mind, Puppet will not know that the groups do not exist, and will attempt to enforce your declared state, regardless.
The fix to this is to create the groups, and enforce explicit dependencies so that they are created before the user is created. To be clear, Puppet does draw implicit dependencies between resources, but I've always found it more helpful to be explicit when referring to other resources for the sake of increasing readability and reducing ambiguity.
group { ['docker', 'www-data']:
ensure => present,
}
user { 'user':
group => ['docker', 'www-data'],
require => Group['docker', 'www-data'],
}
Notes:
- Single quotes should always be used unless the string contains a variable
- The name of the resource should be on the same line as the resource type
- When referring to other resources for dependencies, the first character of the resource type is capitalised