Matteo Bernardini (matteo.bernardini _at_ gmail.com)
(nome di battaglia: ponce)
usa Linux da quasi quattro lustri
esperienza lavorativa in diverse ditte ed enti pubblici italiani
dal 2008 molto attivo su Slackware
(virtualizzazione, ambienti grafici leggeri, desktop remoti)
dal 2012 parte del gruppo di amministratori di SlackBuilds.org
Un po' di storia della virtualizzazione in ambiente x86
1999 - VMware Workstation (ESX Server solo dal 2001)
1999 - User Mode Linux
2000 - FreeBSD supporta le jail
2001 - Linux VServer
2003 - qemu
2003 - Xen
2004 - Solaris Containers
2004 - Linux cpusets
2004 - Innotek Virtualbox
2005 - OpenVZ (Open Virtuozzo)
2005 - libvirt
(continua)
2006 - Linux cgroups
2006 - qemu-kvm
2008 - Proxmox
2008 - Linux user namespaces
2008 - LXC
2013 - docker
2013 - lmctfy
2014 - rkt
Virtualizzazione
con Hypervisor
LXC
I container condividono il kernel dell'host e quindi sono molto meno pesanti della virtualizzazione dell'hardware. Volendo possono usare anche le librerie e i binari del sistema operativo ospitante per far girare applicazioni (ad esempio tramite bind mount).
VANTAGGI DEGLI HYPERVISOR
VANTAGGI DEI CONTAINER
a cosa ci si riferisce con il termine LXC?
da Wikipedia: "LXC (abbreviazione di Linux Containers) è un ambiente di virtualizzazione a container, che opera a livello del sistema operativo e permette di eseguire diversi ambienti Linux virtuali isolati tra loro (container) su una singola macchina Linux reale."
la stessa parola, LXC, è usato anche per indicare l'insieme di strumenti in userspace (reperibili su linuxcontainers.org) per la creazione e la gestione degli stessi container.
i container LXC sfruttano fondamentalmente caratteristiche del kernel Linux perfezionate in tempi relativamente recenti:
CGROUPS
Sono stati scritti da Paul Menage, Rohit Seth e altri ingegneri di Google a partire dal 2006 col nome di "process containers" e forniti come patch al kernel Linux.
Dal 2008, col kernel 2.6.24, sono entrati ufficialmente nel kernel.
Un cgroup (abbreviazione di "control group") è un insieme di processi vincolati dagli stessi criteri e legati da un set di parametri o limiti.
Ogni sottogruppo eredita gerarchicamente i limiti dal genitore.
Si puo' agire su di loro in diversi modi:
i vari sottosistemi disponibili per i cgroups dipendono dai relativi moduli del kernel caricati e l'interfaccia che li rende visibili è nel filesystem /sys. Quelli disponibili nel kernel 4.6 sono:
blkio — imposta i limiti sull'accesso input/output da e per i dispositivi a blocchi come ad esempio le unità fisiche (dischi, solid state, USB, ecc.).
cpu — utilizza lo scheduler per fornire un accesso ai task del cgroup per la CPU.
cpuacct — genera delle notifiche automatiche relative alle risorse della CPU usate dai task di un cgroup.
cpuset — assegna le CPU individuali (su un sistema multicore) ed i nodi della memoria ai task in un cgroup.
devices — permette o nega l'accesso ai dispositivi in base ai task presenti in un cgroup.
freezer — sospende o ripristina i task in un cgroup.
memory — imposta i limiti sull'utilizzo della memoria usata dai task in un cgroup e genera automaticamente le analisi sulle risorse della memoria utilizzata dagli stessi task.
net_cls — etichetta i pacchetti di rete con un identificatore di classe (classid), in grado di permettere al traffic controller (tc) di Linux, di identificare i pacchetti originati da un particolare task del cgroup.
net_prio — assegna priorità di rete a processi anche sulla base dell'interfaccia.
ns — Il sottosistema namespace.
perf_event — estende il modo per-cpu di perf perche' misuri i thread appartenenti allo specifico cgroup e alla cpu specifica.
pids — limita il numero dei processi utilizzabili da un cgroup.
|-- blkio
| |-- blkio.io_merged
| |-- blkio.io_merged_recursive
| |-- blkio.io_queued
| |-- blkio.io_queued_recursive
| |-- blkio.io_service_bytes
| |-- blkio.io_service_bytes_recursive
| |-- blkio.io_service_time
| |-- blkio.io_service_time_recursive
| |-- blkio.io_serviced
| |-- blkio.io_serviced_recursive
| |-- blkio.io_wait_time
| |-- blkio.io_wait_time_recursive
| |-- blkio.leaf_weight
| |-- blkio.leaf_weight_device
| |-- blkio.reset_stats
| |-- blkio.sectors
| |-- blkio.sectors_recursive
| |-- blkio.throttle.io_service_bytes
| |-- blkio.throttle.io_serviced
| |-- blkio.throttle.read_bps_device
| |-- blkio.throttle.read_iops_device
| |-- blkio.throttle.write_bps_device
| |-- blkio.throttle.write_iops_device
| |-- blkio.time
| |-- blkio.time_recursive
| |-- blkio.weight
| |-- blkio.weight_device
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- lxc
| | |-- blkio.io_merged
| | |-- blkio.io_merged_recursive
| | |-- blkio.io_queued
| | |-- blkio.io_queued_recursive
| | |-- blkio.io_service_bytes
| | |-- blkio.io_service_bytes_recursive
| | |-- blkio.io_service_time
| | |-- blkio.io_service_time_recursive
| | |-- blkio.io_serviced
| | |-- blkio.io_serviced_recursive
| | |-- blkio.io_wait_time
| | |-- blkio.io_wait_time_recursive
| | |-- blkio.leaf_weight
| | |-- blkio.leaf_weight_device
| | |-- blkio.reset_stats
| | |-- blkio.sectors
| | |-- blkio.sectors_recursive
| | |-- blkio.throttle.io_service_bytes
| | |-- blkio.throttle.io_serviced
| | |-- blkio.throttle.read_bps_device
| | |-- blkio.throttle.read_iops_device
| | |-- blkio.throttle.write_bps_device
| | |-- blkio.throttle.write_iops_device
| | |-- blkio.time
| | |-- blkio.time_recursive
| | |-- blkio.weight
| | |-- blkio.weight_device
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- notify_on_release
| | |-- provalxc
| | | |-- blkio.io_merged
| | | |-- blkio.io_merged_recursive
| | | |-- blkio.io_queued
| | | |-- blkio.io_queued_recursive
| | | |-- blkio.io_service_bytes
| | | |-- blkio.io_service_bytes_recursive
| | | |-- blkio.io_service_time
| | | |-- blkio.io_service_time_recursive
| | | |-- blkio.io_serviced
| | | |-- blkio.io_serviced_recursive
| | | |-- blkio.io_wait_time
| | | |-- blkio.io_wait_time_recursive
| | | |-- blkio.leaf_weight
| | | |-- blkio.leaf_weight_device
| | | |-- blkio.reset_stats
| | | |-- blkio.sectors
| | | |-- blkio.sectors_recursive
| | | |-- blkio.throttle.io_service_bytes
| | | |-- blkio.throttle.io_serviced
| | | |-- blkio.throttle.read_bps_device
| | | |-- blkio.throttle.read_iops_device
| | | |-- blkio.throttle.write_bps_device
| | | |-- blkio.throttle.write_iops_device
| | | |-- blkio.time
| | | |-- blkio.time_recursive
| | | |-- blkio.weight
| | | |-- blkio.weight_device
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- cgmanager
| `-- sock
|-- cpu
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- cpu.cfs_period_us
| |-- cpu.cfs_quota_us
| |-- cpu.rt_period_us
| |-- cpu.rt_runtime_us
| |-- cpu.shares
| |-- cpu.stat
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- cpu.cfs_period_us
| | |-- cpu.cfs_quota_us
| | |-- cpu.rt_period_us
| | |-- cpu.rt_runtime_us
| | |-- cpu.shares
| | |-- cpu.stat
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- cpu.cfs_period_us
| | | |-- cpu.cfs_quota_us
| | | |-- cpu.rt_period_us
| | | |-- cpu.rt_runtime_us
| | | |-- cpu.shares
| | | |-- cpu.stat
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- cpuacct
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- cpuacct.stat
| |-- cpuacct.usage
| |-- cpuacct.usage_percpu
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- cpuacct.stat
| | |-- cpuacct.usage
| | |-- cpuacct.usage_percpu
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- cpuacct.stat
| | | |-- cpuacct.usage
| | | |-- cpuacct.usage_percpu
| | | `-- tasks
| | `-- tasks
| |-- notify_on_release
| |-- org
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- cpuacct.stat
| | |-- cpuacct.usage
| | |-- cpuacct.usage_percpu
| | |-- freedesktop
| | | |-- ConsoleKit
| | | | |-- Session1
| | | | | |-- cgroup.clone_children
| | | | | |-- cgroup.procs
| | | | | |-- cpuacct.stat
| | | | | |-- cpuacct.usage
| | | | | |-- cpuacct.usage_percpu
| | | | | |-- notify_on_release
| | | | | `-- tasks
| | | | |-- Session2
| | | | | |-- cgroup.clone_children
| | | | | |-- cgroup.procs
| | | | | |-- cpuacct.stat
| | | | | |-- cpuacct.usage
| | | | | |-- cpuacct.usage_percpu
| | | | | |-- notify_on_release
| | | | | `-- tasks
| | | | |-- cgroup.clone_children
| | | | |-- cgroup.procs
| | | | |-- cpuacct.stat
| | | | |-- cpuacct.usage
| | | | |-- cpuacct.usage_percpu
| | | | |-- notify_on_release
| | | | `-- tasks
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- cpuacct.stat
| | | |-- cpuacct.usage
| | | |-- cpuacct.usage_percpu
| | | |-- notify_on_release
| | | `-- tasks
| | |-- notify_on_release
| | `-- tasks
| |-- release_agent
| `-- tasks
|-- cpuset
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- cpuset.cpu_exclusive
| |-- cpuset.cpus
| |-- cpuset.effective_mems
| |-- cpuset.mem_exclusive
| |-- cpuset.mem_hardwall
| |-- cpuset.memory_migrate
| |-- cpuset.memory_pressure
| |-- cpuset.memory_pressure_enabled
| |-- cpuset.memory_spread_page
| |-- cpuset.memory_spread_slab
| |-- cpuset.mems
| |-- cpuset.sched_load_balance
| |-- cpuset.sched_relax_domain_level
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- cpuset.cpu_exclusive
| | |-- cpuset.cpus
| | |-- cpuset.effective_cpus
| | |-- cpuset.effective_mems
| | |-- cpuset.mem_exclusive
| | |-- cpuset.mem_hardwall
| | |-- cpuset.memory_migrate
| | |-- cpuset.memory_pressure
| | |-- cpuset.memory_spread_page
| | |-- cpuset.memory_spread_slab
| | |-- cpuset.mems
| | |-- cpuset.sched_load_balance
| | |-- cpuset.sched_relax_domain_level
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- cpuset.cpu_exclusive
| | | |-- cpuset.cpus
| | | |-- cpuset.effective_cpus
| | | |-- cpuset.effective_mems
| | | |-- cpuset.mem_exclusive
| | | |-- cpuset.mem_hardwall
| | | |-- cpuset.memory_migrate
| | | |-- cpuset.memory_pressure
| | | |-- cpuset.memory_spread_page
| | | |-- cpuset.memory_spread_slab
| | | |-- cpuset.mems
| | | |-- cpuset.sched_load_balance
| | | |-- cpuset.sched_relax_domain_level
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- devices
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- devices.allow
| |-- devices.deny
| |-- devices.list
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- devices.allow
| | |-- devices.deny
| | |-- devices.list
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- devices.allow
| | | |-- devices.deny
| | | |-- devices.list
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- freezer
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- freezer.parent_freezing
| | |-- freezer.self_freezing
| | |-- freezer.state
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- freezer.parent_freezing
| | | |-- freezer.self_freezing
| | | |-- freezer.state
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- memory
| |-- cgroup.clone_children
| |-- cgroup.event_control
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.event_control
| | |-- cgroup.procs
| | |-- memory.failcnt
| | |-- memory.force_empty
| | |-- memory.kmem.failcnt
| | |-- memory.kmem.limit_in_bytes
| | |-- memory.kmem.max_usage_in_bytes
| | |-- memory.kmem.slabinfo
| | |-- memory.kmem.tcp.failcnt
| | |-- memory.kmem.tcp.limit_in_bytes
| | |-- memory.kmem.tcp.max_usage_in_bytes
| | |-- memory.kmem.tcp.usage_in_bytes
| | |-- memory.kmem.usage_in_bytes
| | |-- memory.limit_in_bytes
| | |-- memory.max_usage_in_bytes
| | |-- memory.move_charge_at_immigrate
| | |-- memory.oom_control
| | |-- memory.pressure_level
| | |-- memory.soft_limit_in_bytes
| | |-- memory.stat
| | |-- memory.swappiness
| | |-- memory.usage_in_bytes
| | |-- memory.use_hierarchy
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.event_control
| | | |-- cgroup.procs
| | | |-- memory.failcnt
| | | |-- memory.force_empty
| | | |-- memory.kmem.failcnt
| | | |-- memory.kmem.limit_in_bytes
| | | |-- memory.kmem.max_usage_in_bytes
| | | |-- memory.kmem.slabinfo
| | | |-- memory.kmem.tcp.failcnt
| | | |-- memory.kmem.tcp.limit_in_bytes
| | | |-- memory.kmem.tcp.max_usage_in_bytes
| | | |-- memory.kmem.tcp.usage_in_bytes
| | | |-- memory.kmem.usage_in_bytes
| | | |-- memory.limit_in_bytes
| | | |-- memory.max_usage_in_bytes
| | | |-- memory.move_charge_at_immigrate
| | | |-- memory.oom_control
| | | |-- memory.pressure_level
| | | |-- memory.soft_limit_in_bytes
| | | |-- memory.stat
| | | |-- memory.swappiness
| | | |-- memory.usage_in_bytes
| | | |-- memory.use_hierarchy
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- memory.failcnt
| |-- memory.force_empty
| |-- memory.kmem.failcnt
| |-- memory.kmem.limit_in_bytes
| |-- memory.kmem.max_usage_in_bytes
| |-- memory.kmem.slabinfo
| |-- memory.kmem.tcp.failcnt
| |-- memory.kmem.tcp.limit_in_bytes
| |-- memory.kmem.tcp.max_usage_in_bytes
| |-- memory.kmem.tcp.usage_in_bytes
| |-- memory.kmem.usage_in_bytes
| |-- memory.limit_in_bytes
| |-- memory.max_usage_in_bytes
| |-- memory.move_charge_at_immigrate
| |-- memory.oom_control
| |-- memory.pressure_level
| |-- memory.soft_limit_in_bytes
| |-- memory.stat
| |-- memory.swappiness
| |-- memory.usage_in_bytes
| |-- memory.use_hierarchy
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- net_cls
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- net_cls.classid
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- net_cls.classid
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- net_cls.classid
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- net_prio
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- net_prio.ifpriomap
| | |-- net_prio.prioidx
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- net_prio.ifpriomap
| | | |-- net_prio.prioidx
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- net_prio.ifpriomap
| |-- net_prio.prioidx
| |-- notify_on_release
| |-- release_agent
| `-- tasks
|-- perf_event
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- cgroup.sane_behavior
| |-- lxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- notify_on_release
| | |-- provalxc
| | | |-- cgroup.clone_children
| | | |-- cgroup.procs
| | | |-- notify_on_release
| | | `-- tasks
| | `-- tasks
| |-- notify_on_release
| |-- release_agent
| `-- tasks
`-- pids
|-- cgroup.clone_children
|-- cgroup.procs
|-- cgroup.sane_behavior
|-- lxc
| |-- cgroup.clone_children
| |-- cgroup.procs
| |-- notify_on_release
| |-- pids.current
| |-- pids.max
| |-- provalxc
| | |-- cgroup.clone_children
| | |-- cgroup.procs
| | |-- notify_on_release
| | |-- pids.current
| | |-- pids.max
| | `-- tasks
| `-- tasks
|-- notify_on_release
|-- release_agent
`-- tasks
* mount sottosistema cgroups
* istanza cgroup
* container
si può agire su questa interfaccia in lettura e scrittura.
Partizionare l'uso della CPU
Fare il pinning della cpu per particolari processi
Limitare l'accesso ai device
NAMESPACES
Un namespace ingloba una risorsa globale del sistema in una forma di astrazione in modo tale da farla apparire isolata ai processi all'interno dello stesso.
Le modifiche alla risorsa globale sono visibili agli altri processi membri del namespace ma invisibili agli altri.
È possibile lasciare la possibilità di connettersi al namespace genitore.
La API dei namespaces consiste in tre chiamate di sistema, clone(), unshare() e setns(), e dei file in /proc (/proc/$PID/ns).
Namespace | Costante | Cosa Isola |
---|---|---|
IPC | CLONE_NEWIPC | IPC System V, code messaggi POSIX |
Network | CLONE_NEWNET | Perif. rete, stack, porte, routing, ecc. |
Mount | CLONE_NEWNS | Punti di mount, filesystem |
PID | CLONE_NEWPID | ID processo |
User | CLONE_NEWUSER | ID utente e gruppo |
UTS | CLONE_NEWUTS | Nome host e dominio NIS |
LE CAPABILITIES
Permettono un controllo preciso sui permessi di superuser, descrivendo cosa può e cosa non può fare. Servono, ad esempio, per evitare di dover usare binari con SUID.
Sono supportate anche a livello di filesystem.
Ce ne sono moltissime a disposizione: un elenco completo è disponibile da shell con un "man 7 capabilities"
http://man7.org/linux/man-pages/man7/capabilities.7.html
per l'utilizzo dei namespaces, tranne che per lo USER namespace, è richiesta la CAP_SYS_ADMIN
namespace MNT
Isola la tabella di mount, rendendo possibili mount specifici al namespace: le operazioni di mount e umount rimangono isolate.
È possibile regolare la propagazione dei mount:
molti strumenti (tra cui il comando mount) lo supportano ed in genere è usato con chroot e pivot_root per isolare il filesystem di root di un processo/container.
namespace UTS
Permette ai container di avere un loro FQDN.
namespace PID
Opera una mappatura degli ID di processo specifica per il namespace.
All'interno del namespace sono visibili solo i processi dello stesso.
namespace IPC
Isolamento degli oggetti IPC System V e delle code POSIX dei messaggi tra i namespaces (semafori, memoria condivisa, code).
Ci si può connettere col namespace padre tramite segnali, polling della memoria, socket (se non isolati dal namespace NET), descrittori dei file (se non isolati dal namespace MOUNT), eventi trasmessi via pipe.
namespace NET
Oggetti di rete specifici per il namespace (periferiche, bridge, tabelle di routing, indirizzi IP, porte, ecc.).
Supportato da diversi comandi tra cui ip (di iproute2).
Si può usare, ad esempio, per connettersi tra due namespaces, creando una coppia di veth (virtual ethernet device) e usandole come pipe.
namespace USER
Unico a non richiedere privilegi particolari, permette agli utenti non privilegiati di instanziare container LXC, mappando UID e GID dentro e fuori dai container (si possono impostare anche staticamente tramite file di configurazione, /etc/subuid e /etc/subgid).
L'implementazione da parte di Eric Biedermann e' stato un lavoro immenso e lunghissimo: la grossa quantità di codice scritto da zero li rende un po' delicati. Ma la prospettiva futura è invece una mitigazione dei problemi di sicurezza dei container. Non sono ancora ufficialmente supportati.
CHROOT
Cambia la cartella radice per i processi e per i loro figli (percorsi di ricerca, assoluti, ecc.).
È possibile sfuggire a un chroot avendo le necessarie capabilities e quindi è preferibile usare pivot_root che fa uno switch completo sulla nuova root.
LXC in pratica fa un bind mount del filesystem di root del container e lancia il processo di init di LXC in un nuovo namespace MNT con un pivot_root al bind mount.
L'uso di pivot_root insieme al namespace MNT impedisce la fuga dalla nuova root.
I LINUX SECURITY MODULES E IL MAC
Consistono in moduli kernel che implementano dei framework per il Mandatory Access Control (MAC).
In genere sono basati su profili (personalizzabili).
i tool LXC supportano Apparmor, SELinux, Seccomp.
Altre misure (alcune già accennate):
LXC (gli strumenti userspace - non la tecnologia!)
Sono disponibili una API C, liblxc (lxccontainer.h), e alcuni bindings per vari linguaggi tra cui python e lua: in passato alcune utility fornite li utilizzavano (lxc-ls, ad esempio) ma è in corso una riscrittura in C.
Sono supportati nativamente diversi tipi di storage dalla versione 1.0:
directory
btrfs
lvm
overlayfs
zfs
/etc/lxc/lxc.conf e' il file di configurazione generale in cui si definisce, per esempio, il percorso dei container (che comunque è impostabile a mano nei file di configurazione).
Di default i rootfs dei container sono in /var/lib/lxc in delle sottodirectory chiamate col nome del container che contengono anche i file di configurazioni specifici degli stessi.
# ls -1 /var/lib/lxc/
provalxc
# ls -1 /var/lib/lxc/provalxc/
config
rootfs
# ls -1 /var/lib/lxc/provalxc/rootfs/
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# cat /var/lib/lxc/provalxc/config
# Template used to create this container: /usr/share/lxc/templates/lxc-slackware
# Parameters passed to the template:
# For additional config options, please look at lxc.container.conf(5)
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.hwaddr = 00:aa:11:bb:22:cc
lxc.network.ipv4 = 192.168.111.2/24
lxc.network.name = eth0
lxc.rootfs = /var/lib/lxc/provalxc/rootfs
lxc.start.auto = 1
lxc.utsname = provalxc
lxc.mount = /var/lib/lxc/provalxc/rootfs/etc/fstab
lxc.tty = 4
lxc.pts = 1024
lxc.rootfs = /var/lib/lxc/provalxc/rootfs
lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
# we don't trust even the root user in the container, better safe than sorry.
# comment out only if you know what you're doing.
lxc.cap.drop = sys_module mknod mac_override mac_admin sys_time setfcap setpcap
# you can try also this alternative to the line above, whatever suits you better.
# lxc.cap.drop=sys_admin
LXD
Sviluppato in go tramite i binding di liblxc, è un'alternativa ai tool lxc e al sistema di distribuzione a template, col valore aggiunto di essere controllabile via rete.
Ha fondamentalmente tre componenti: un demone di sistema, un client a linea di comando e un plugin per OpenStack Nova.
Le sue caratteristiche più evidenti:
È un progetto di Canonical.
LIBVIRT-LXC
Libvirt può usare LXC connettendosi a lxc:/// il supporto però è limitato rispetto ai tool ufficiali (non si possono fare snapshot, non supporta template, ecc.)
DOCKER
Strumento alternativo ai tool LXC il cui scopo principale è pacchettizzare un'applicazione e le sue dipendenze in un container virtuale che può essere eseguito più o meno ovunque.
Fornisce API per la gestione dei suoi container e permette di fare il deployment di nuovi nodi/istanze a richiesta, per questo si parla di Platform as a Service (PaaS).
Può essere integrato in varie infrastrutture, tra cui Amazon Web Services, Ansible, CFEngine, Chef, Google Cloud Platform, IBM Bluemix, Jelastic, Jenkins, Microsoft Azure, NoMachine, OpenStack Nova, OpenSVC, Puppet, Salt e Vagrant.
Prima usava gli stessi tool LXC per la gestione interna dei container, poi ha sviluppato una sua libreria, libcontainer.
Da qualche tempo libcontainer e' stata inglobata in runC della Open Container Initiative, un progetto per standardizzare i container coordinato dalla Linux Foundation a cui hanno aderito praticamente tutti i vendor.
runC e' un'implementazione delle specifiche OCI.
Il formato delle immagini dei container sara' l'OCF.
per maggiori informazioni fare riferimento a github
https://github.com/opencontainers
gli obbiettivi sono di creare container che siano:
Docker è considerato da molti la versione "facile" di LXC che piace agli sviluppatori di applicazioni.
Le immagini dei container docker sono fatte per girare ovunque vengano eseguite mentre le immagini dei container LXC dipendono dai setup locali e necessitano spesso di rimaneggiamenti a seguito di trasferimenti.
Il punto focale di docker è l'applicazione che gira nel container più che lo stesso container nel suo insieme.
Supporta il versioning anche tramite filesystem a layer, come overlayfs.
Oltre che tramite la linea di comando, si può interagire con docker tramite una API REST.
Si punta molto sul riutilizzo, ogni immagine può essere salvata e distribuita: il punto centrale di scambio è hub.docker.com.
Lo scopo è fornire pacchetti completi sistemi operativi / applicazioni senza doversi più preoccupare delle dipendenze.
Ovviamente questo approccio ha anche degli svantaggi: sentiamo cosa pensa al riguardo un famoso CEO a cui lasciamo anche il compito di tirare le conclusioni ;-)
Risorse per approfondire
Un ringraziamento particolare va a Boden Russell, la cui presentazione,
"Realizing Linux Containers (LXC) - Building Blocks, Underpinnings & Motivations",
ha giocato una parte importante nella realizzazione di queste slide