Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing a new docker class without network namespace #120

Merged
merged 28 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f5df4e4
Attempt to create a new dockerhost class
theseal Jan 17, 2024
eecb4f6
Firewall rules for new class
theseal Jan 17, 2024
74173cf
Configure everything though daemon.json
theseal Jan 17, 2024
4b50826
Syntax error
theseal Jan 17, 2024
7a95581
Clean up old files from legacy class
theseal Jan 17, 2024
1c2c6e8
Not in use - what I can find
theseal Jan 17, 2024
bfe661d
Make sure configuration is up to date before installation of package
theseal Jan 17, 2024
1561b92
Don't empty the variable
theseal Jan 17, 2024
d326e1d
JSON
theseal Jan 17, 2024
6a79239
Set forward flag if needed
theseal Jan 17, 2024
b9f5588
Never ever touch the firewall
theseal Jan 17, 2024
87611cc
We handle the NATing
theseal Jan 17, 2024
cfa7402
Better name
theseal Jan 17, 2024
875191e
Indentation
theseal Jan 17, 2024
edc850a
Remove file if we don't nat any more
theseal Jan 17, 2024
8a92ab3
Syntax error
theseal Jan 17, 2024
087e9bb
Always configure ipv6
theseal Jan 17, 2024
a3e2c90
Start the migration from the ufw namespace
theseal Jan 17, 2024
39af309
Relay on the systems resolvers
theseal Jan 17, 2024
fe33258
A string can't be undef
theseal Jan 17, 2024
c9af152
Support the new shiny dockerhost class
theseal Jan 18, 2024
0fbdd5e
We only support modern dists
theseal Jan 18, 2024
1c8e29d
Start using docker compose v2 for new docker class
theseal Jan 18, 2024
081cda3
Instruct the service to use the correct template
theseal Jan 18, 2024
c322a6a
Exact match?
theseal Jan 18, 2024
0e70ce1
I'm just stupid
theseal Jan 18, 2024
0340921
Make transition to dockerhost2 easier
theseal Jan 18, 2024
bc4aefb
Update unused command with new syntax
theseal Jan 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions facts.d/sunet_dockerhost2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python3

import os
import yaml
import re
import sys
import socket


def iteritems(d):
return iter(d.items())


def _all_hosts():
return list(
filter(
lambda fn: "." in fn
and not fn.startswith(".")
and os.path.isdir("/var/cache/cosmos/repo/" + fn),
os.listdir("/var/cache/cosmos/repo"),
)
)


rules = dict()
rules_file = "/etc/puppet/cosmos-rules.yaml"
if os.path.exists(rules_file):
with open(rules_file) as fd:
rules.update(yaml.load(fd, Loader=yaml.FullLoader))

all_hosts = _all_hosts()

me = socket.gethostbyaddr(socket.gethostname())[0]
for node_name in all_hosts:
for reg, cls in iteritems(rules):
if re.match(reg, node_name):
if node_name == me:
if "sunet::dockerhost2" in cls:
print("dockerhost2=yes")
sys.exit()

print("dockerhost2=no")
24 changes: 17 additions & 7 deletions manifests/docker_compose.pp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@
String $owner = 'root',
Optional[String] $start_command = undef,
) {
$nftenabled_and_interface = $::facts['sunet_nftables_enabled'] == 'yes' and has_key($::facts['networking']['interfaces'], 'to_docker')
$advanced_network_or_nftdisabled = $::facts['dockerhost_advanced_network'] == 'yes' or $::facts['sunet_nftables_enabled'] == 'no'
if ( $nftenabled_and_interface or $advanced_network_or_nftdisabled ) {
$_install_service = true

$docker_class = $::facts['dockerhost2'] ? {
no => 'sunet::dockerhost',
default => 'sunet::dockerhost2',
}
if ($docker_class == 'sunet::dockerhost') {
# handle legacy class
$nftenabled_and_interface = $::facts['sunet_nftables_enabled'] == 'yes' and has_key($::facts['networking']['interfaces'], 'to_docker')
$advanced_network_or_nftdisabled = $::facts['dockerhost_advanced_network'] == 'yes' or $::facts['sunet_nftables_enabled'] == 'no'
if ( $nftenabled_and_interface or $advanced_network_or_nftdisabled ) {
$_install_service = true
} else {
$_install_service = false
notice("sunet::docker_compose: Not installing ${service_name}, interface to_docker missing")
}
} else {
$_install_service = false
notice("sunet::docker_compose: Not installing ${service_name}, interface to_docker missing")
$_install_service = true
}

if $_install_service {
Expand All @@ -31,7 +41,7 @@
ensure => 'file',
mode => '600',
content => $content,
require => Class['sunet::dockerhost'],
require => Class[$docker_class],
})

sunet::docker_compose_service { "${service_prefix}-${service_name}":
Expand Down
43 changes: 22 additions & 21 deletions manifests/docker_compose_service.pp
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,30 @@
Array[String] $service_extras = [],
Optional[String] $start_command = undef,
) {
if ($::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemrelease, '15.04') >= 0) or $::operatingsystem == 'Debian' {
include sunet::systemd_reload
include sunet::systemd_reload

$_service_name = $service_name ? {
undef => $name,
default => $service_name,
}
$_service_name = $service_name ? {
undef => $name,
default => $service_name,
}

$_template = $::facts['dockerhost2'] ? {
no => 'sunet/dockerhost/compose.service.erb',
default => 'sunet/dockerhost/compose2.service.erb',
}

file {
"/etc/systemd/system/${_service_name}.service":
content => template('sunet/dockerhost/compose.service.erb'),
notify => [Class['sunet::systemd_reload'],
],
;
}
file {
"/etc/systemd/system/${_service_name}.service":
content => template($_template),
notify => [Class['sunet::systemd_reload'],
],
;
}

service { $_service_name :
ensure => 'running',
enable => true,
require => File["/etc/systemd/system/${_service_name}.service"],
provider => 'systemd', # puppet is really bad at figuring this out
}
} else {
err('sunet::docker_compose_service only available on Ubuntu >= 15.04 for now (only systemd is implemented)')
service { $_service_name :
ensure => 'running',
enable => true,
require => File["/etc/systemd/system/${_service_name}.service"],
provider => 'systemd', # puppet is really bad at figuring this out
}
}
178 changes: 178 additions & 0 deletions manifests/dockerhost2.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# Install docker from https://get.docker.com/ubuntu
class sunet::dockerhost2(
String $docker_version = 'installed',
String $docker_package_name = 'docker-ce',
Enum['stable', 'edge', 'test'] $docker_repo = 'stable',
Boolean $run_docker_cleanup = true,
String $docker_network = lookup('dockerhost_docker_network', String, undef, '172.16.0.0/12'),
String $docker_network_v6 = lookup('dockerhost_docker_network_v6', String, undef, 'fd0c:d0c::/64'), # default bridge
Variant[String,Boolean] $docker_dns = lookup('dockerhost_docker_dns', undef, undef,false),
Boolean $ipv6 = true,
Boolean $nat = true,
) {

include sunet::packages::jq # restart_unhealthy_containers requirement
include sunet::packages::python3_yaml # check_docker_containers requirement


# Start of Migration from sunet::dockerhost
file {'/etc/systemd/system/docker.service.d/docker_nftables_ns.conf':
ensure => 'absent',
}
file {'/etc/systemd/system/docker.service.d/service-overrides.conf':
ensure => 'absent',
}
file {'/etc/default/docker':
ensure => 'absent',
}
# End of Migration from sunet::dockerhost

if ($nat) {
file {
'/etc/nftables/conf.d/200-sunet_dockerhost.nft':
ensure => file,
mode => '0400',
content => template('sunet/dockerhost/200-dockerhost2_nftables.nft.erb'),
notify => Service['nftables'],
;
}
} else {
file {'/etc/nftables/conf.d/200-sunet_dockerhost.nft':
ensure => 'absent',
notify => Service['nftables'],
}
}

file {
'/etc/docker':
ensure => 'directory',
mode => '0755',
;
'/etc/docker/daemon.json':
ensure => file,
mode => '0644',
content => template('sunet/dockerhost/daemon2.json.erb'),
;
}

# Add the dockerproject repository, then force an apt-get update before
# trying to install the package. See https://tickets.puppetlabs.com/browse/MODULES-2190.
#
sunet::misc::create_dir { '/etc/cosmos/apt/keys': owner => 'root', group => 'root', mode => '0755'}
file {
'/etc/cosmos/apt/keys/docker_ce-8D81803C0EBFCD88.pub':
ensure => file,
mode => '0644',
content => template('sunet/dockerhost/docker_ce-8D81803C0EBFCD88.pub.erb'),
;
}
apt::key { 'docker_ce':
id => '9DC858229FC7DD38854AE2D88D81803C0EBFCD88',
server => 'https://does-not-exists-but-is-required.example.com',
source => '/etc/cosmos/apt/keys/docker_ce-8D81803C0EBFCD88.pub',
notify => Exec['dockerhost_apt_get_update'],
}

$distro = downcase($facts['os']['name'])
# new source
apt::source {'docker_ce':
location => "https://download.docker.com/linux/${distro}",
release => $facts['os']['distro']['codename'],
repos => $docker_repo,
key => {'id' => '9DC858229FC7DD38854AE2D88D81803C0EBFCD88'},
notify => Exec['dockerhost_apt_get_update'],
}

apt::pin { 'Pin docker repo':
packages => '*',
priority => 1,
origin => 'download.docker.com'
}

exec { 'dockerhost_apt_get_update':
command => '/usr/bin/apt-get update',
cwd => '/tmp',
refreshonly => true,
}

package { $docker_package_name :
ensure => $docker_version,
require => Exec['dockerhost_apt_get_update'],
}
package { 'docker-ce-cli' :
ensure => $docker_version,
require => Exec['dockerhost_apt_get_update'],
}

file {
'/etc/logrotate.d':
ensure => 'directory',
mode => '0755',
;
'/etc/logrotate.d/docker-containers':
ensure => file,
path => '/etc/logrotate.d/docker-containers',
mode => '0644',
content => template('sunet/dockerhost/logrotate_docker-containers.erb'),
;
}

file { '/usr/local/bin/docker-upgrade':
ensure => 'present',
mode => '0755',
source => 'puppet:///modules/sunet/docker/docker-upgrade',
}

if $facts['sunet_has_nrpe_d'] == 'yes' {
# variables used in etc_sudoers.d_nrpe_dockerhost_checks.erb / nagios_nrpe_checks.erb
$check_docker_containers_args = '--systemd'

file {
'/etc/sudoers.d/nrpe_dockerhost_checks':
ensure => file,
mode => '0440',
content => template('sunet/dockerhost/etc_sudoers.d_nrpe_dockerhost_checks.erb'),
;
'/etc/nagios/nrpe.d/sunet_dockerhost_checks.cfg':
ensure => 'file',
content => template('sunet/dockerhost/nagios_nrpe_checks.erb'),
notify => Service['nagios-nrpe-server'],
;
'/usr/local/bin/check_docker_containers':
ensure => file,
mode => '0755',
content => template('sunet/dockerhost/check_docker_containers.erb'),
;
'/usr/local/bin/restart_unhealthy_containers':
ensure => file,
mode => '0755',
content => template('sunet/dockerhost/restart_unhealthy_containers.erb'),
;
'/usr/local/bin/check_for_updated_docker_image':
ensure => file,
mode => '0755',
content => template('sunet/dockerhost/check_for_updated_docker_image.erb'),
;
}
}

if $run_docker_cleanup {
# Cron job to remove old unused docker images
sunet::scriptherder::cronjob { 'dockerhost_cleanup':
cmd => join([
'docker run --rm -v /var/run/docker.sock:/var/run/docker.sock',
'docker.sunet.se/sunet/docker-custodian dcgc',
'--exclude-image \'*:latest\'',
'--exclude-image \'*:staging\'',
'--exclude-image \'*:stable\'',
'--exclude-image \'*:*-staging\'',
'--exclude-image \'*:*-production\'',
'--max-image-age 24h',
], ' '),
special => 'daily',
ok_criteria => ['exit_status=0', 'max_age=25h'],
warn_criteria => ['exit_status=0', 'max_age=49h'],
}
}

}
14 changes: 14 additions & 0 deletions manifests/nftables/allow.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Open host firewall to allow clients to access a service.
define sunet::nftables::allow(
$from, # Allow traffic 'from' this IP (or list of IP:s).
$port, # Allow traffic to this port (or list of ports).
$to = 'any', # Allow traffic to this IP (or list of IP:s). 'any' means both IPv4 and IPv6.
$proto = 'tcp', # Allow traffic using this protocol (or list of protocols).
) {
ensure_resource('sunet::nftables::ufw_allow_compat', $name, {
from => $from,
to => $to,
proto => $proto,
port => $port,
})
}
41 changes: 41 additions & 0 deletions templates/dockerhost/200-dockerhost2_nftables.nft.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
table ip nat {
chain output {
type nat hook output priority -100; policy accept;
}
chain prerouting {
type nat hook prerouting priority -100; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
}
}
table ip6 nat {
chain output {
type nat hook output priority -100; policy accept;
}
chain prerouting {
type nat hook prerouting priority -100; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
}
}

#
# SNAT packages _from_ Docker.
#
add rule ip nat postrouting ip saddr { 172.16.0.0/12 } iifname docker0 counter masquerade comment "SNAT traffic from Docker"
add rule ip6 nat postrouting ip6 saddr { fd00::2/128 } iifname docker0 counter masquerade comment "SNAT traffic from Docker"
add rule ip6 nat postrouting ip6 saddr { fd0c::/16 } iifname docker0 counter masquerade comment "SNAT traffic from Docker"

#
# Allow forwarding packages from docker
#
add rule inet filter forward ct state established counter accept
add rule inet filter forward iifname docker0 counter accept comment "Forward traffic from Docker"

#
# Allow ICMP to Docker. Necessary for path-mtu at least.
#
add rule inet filter forward oifname docker0 ip protocol icmp counter accept comment "Allow ICMP to Docker"
add rule inet filter forward oifname docker0 ip6 nexthdr icmpv6 counter accept comment "Allow ICMP to Docker"
Loading
Loading