Container con LXC

Virtualizzazione senza le macchine virtuali

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

 

  • si possono emulare sistemi operativi diversi da quello che gira sull'host virtualizzatore (Windows, i BSD, ecc.)
  • in generale sono considerati più sicuri, essendo più diffusi e piu' "anziani" (anche se ogni tanto esce qualche grossa vulnerabilita')

 

VANTAGGI DEI CONTAINER

 

  • le risorse occupate sono sensibilmente minori
  • se ne possono installare molti di più su un determinato hardware
  • sono molto più maneggevoli (tempi di avvio e spegnimento veloci, provisioning piu' semplice)

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:

 

  • i cgroups, tramite i quali si possono imporre limiti, dare priorità,  contabilizzare e controllare;

 

  • i namespaces, che offrono l'isolamento delle risorse basato sui processi;

 

  • la possibilità di usare chroot (cambiare la root operativa dei processi) in modo sicuro;

 

  • i Linux Security Modules (LSM), implementando forme di Mandatory Access Control (MAC).

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:

  • tramite libcgroup, con il "rules engine daemon" o creandoli e gestendoli al volo (cgcreate, cgexec, e cgclassify) 
  • tramite cgmanager (il client si chiama cgm)
  • tramite altro software che li utilizza (LXC, Docker, libvirt, systemd, ecc.)
  • direttamente, agendo sulla loro interfaccia primaria nel filesystem

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

  • la radice del sottosistema per ogni controller
  • si segue una gerarchia padre-figlio (agendo sul padre si influenzano i figli)
  • tutti i processi della macchina sono visibili su "tasks"

* istanza cgroup

  • individuale (lxc, nell'esempio)
  • contiene tutti gli pseudo-file del sottosistema                  

* container

  • anche questa individuale e con i file del sottosistema
  • i processi specifici dei container sono visibili anch'essi su "tasks"

 

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:

  • Shared: gli oggetti del mount propagano eventi in modo bidirezionale;
  • Slave: un mount propaga verso un altro ma non il contrario;
  • Private (predefinito): nessuna propagazione.

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.

  • il PID 1 nel namespace figlio non è lo stesso del genitore;
  • non ci sono conflitti di PID fra i vari namespace;
  • in questo modo in realtà i PID sono 2, uno interno al namespace e l'altro esterno.

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):

  • Restringere le capabilities;                                                             
  • Mount in sola lettura;
  • Container eseguiti da utente.

 

LXC (gli strumenti userspace - non la tecnologia!)

 

  • lxc-create - per assemblare i filesystem dei container o scaricarne versioni prefabbricate ("-t download"). Ci sono molti template disponibili, per le maggiori distribuzioni. Supporta diversi parametri, alcuni variabili a seconda del template scelto;
  • lxc-start - per avviare i container. Restituisce la console del container se non avviato con l'opzione -d (detach);
  • lxc-stop - per fermare i container;
  • lxc-attach - per eseguire comandi all'interno dei container;
  • lxc-ls - restituisce la lista dei container;
  • lxc-top - top per i container;
  • lxc-clone - clona un container;
  • lxc-checkconfig - controlla il supporto per i container nel kernel che sta girando.
  • lxc-snapshot - crea uno snapshot del container

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:

  • Sicurezza (container non privilegiati, controllo sulle risorse, ecc.)
  • Scalabilità
  • Semplicità (API REST e linea di comando)
  • Immagini prefabbricate (via i template solo immagini verificate)
  • Migrazione live

È 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.)

 

  • virsh -c lxc:/// define myguest.xml
  • virsh -c lxc:/// dumpxml myguest
  • virsh -c lxc:/// start myguest
  • virsh -c lxc:/// create myguest.xml # senza configurazione persistente
  • virsh -c lxc:/// shutdown myguest
  • virsh -c lxc:/// destroy myguest
  • virsh -c lxc:/// reboot myguest
  • virsh -c lxc:/// undefine myguest
  • virsh -c lxc:/// console myguest
  • virsh -c lxc:/// lxc-enter-namespace myguest -- /bin/ls -al /dev
  • virt-top -c lxc:///

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:

  • scollegati da costrutti di alto livello come un client o un sistema di orchestrazione specifici
  • non associabili in modo stretto con un vendor o un progetto specifico
  • portabile su una vasta gamma di sistemi operativi, hardware, architetture, cloud pubbliche, ecc.

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 ;-)

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

Container con LXC

By Matteo Bernardini

Container con LXC

  • 2,581