2014-08-30 22 views
7

Mi piacerebbe creare un'immagine Docker senza docker. Ho guardato a Packer, ma è necessario che Docker sia installato sull'host del builder.Formato immagine Docker

Ho visto lo Docker Registry API documentation ma questa informazione non sembra essere lì.

Immagino che l'immagine sia semplicemente un tarball, ma mi piacerebbe vedere una specifica completa del formato, vale a dire quale formato esatto è richiesto e dove ci sono tutti i file di metadati richiesti. Potrei provare a scaricare un'immagine dal registro e cercare cosa c'è dentro, ma non ci sono informazioni su come recuperare l'immagine stessa.

L'idea del mio progetto è di implementare uno script che crea un'immagine da atefacts che ho compilato e la carica nel registro. Mi piacerebbe utilizzare OpenEmbedded per questo scopo, essenzialmente questa sarebbe un'estensione a Bitbake.

risposta

4

Dopo aver letto James Coyle's blog, ho capito che i comandi docker save e docker load sono ciò di cui ho bisogno.

> docker images 
REPOSITORY   TAG     IMAGE ID   CREATED    VIRTUAL SIZE 
progrium/consul  latest    e9fe5db22401  11 days ago   25.81 MB 
> docker save e9fe5db22401 | tar x 
> ls e9fe5db22401* 
VERSION json layer.tar 

Il file contiene solo VERSION1.0, e json contiene un bel po 'di informazioni:

{ 
    "id": "e9fe5db224015ddfa5ee9dbe43b414ecee1f3108fb6ed91add11d2f506beabff", 
    "parent": "68f9e4929a4152df9b79d0a44eeda042b5555fbd30a36f98ab425780c8d692eb", 
    "created": "2014-08-20T17:54:30.98176344Z", 
    "container": "3878e7e9b9935b7a1988cb3ebe9cd45150ea4b09768fc1af54e79b224bf35f26", 
    "container_config": { 
    "Hostname": "7f17ad58b5b8", 
    "Domainname": "", 
    "User": "", 
    "Memory": 0, 
    "MemorySwap": 0, 
    "CpuShares": 0, 
    "Cpuset": "", 
    "AttachStdin": false, 
    "AttachStdout": false, 
    "AttachStderr": false, 
    "PortSpecs": null, 
    "ExposedPorts": { 
     "53/udp": {}, 
     "8300/tcp": {}, 
     "8301/tcp": {}, 
     "8301/udp": {}, 
     "8302/tcp": {}, 
     "8302/udp": {}, 
     "8400/tcp": {}, 
     "8500/tcp": {} 
    }, 
    "Tty": false, 
    "OpenStdin": false, 
    "StdinOnce": false, 
    "Env": [ 
     "HOME=/", 
     "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 
     "SHELL=/bin/bash" 
    ], 
    "Cmd": [ 
     "/bin/sh", 
     "-c", 
     "#(nop) CMD []" 
    ], 
    "Image": "68f9e4929a4152df9b79d0a44eeda042b5555fbd30a36f98ab425780c8d692eb", 
    "Volumes": { 
     "/data": {} 
    }, 
    "WorkingDir": "", 
    "Entrypoint": [ 
     "/bin/start" 
    ], 
    "NetworkDisabled": false, 
    "OnBuild": [ 
     "ADD ./config /config/" 
    ] 
    }, 
    "docker_version": "1.1.2", 
    "author": "Jeff Lindsay <[email protected]>", 
    "config": { 
    "Hostname": "7f17ad58b5b8", 
    "Domainname": "", 
    "User": "", 
    "Memory": 0, 
    "MemorySwap": 0, 
    "CpuShares": 0, 
    "Cpuset": "", 
    "AttachStdin": false, 
    "AttachStdout": false, 
    "AttachStderr": false, 
    "PortSpecs": null, 
    "ExposedPorts": { 
     "53/udp": {}, 
     "8300/tcp": {}, 
     "8301/tcp": {}, 
     "8301/udp": {}, 
     "8302/tcp": {}, 
     "8302/udp": {}, 
     "8400/tcp": {}, 
     "8500/tcp": {} 
    }, 
    "Tty": false, 
    "OpenStdin": false, 
    "StdinOnce": false, 
    "Env": [ 
     "HOME=/", 
     "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 
     "SHELL=/bin/bash" 
    ], 
    "Cmd": [], 
    "Image": "68f9e4929a4152df9b79d0a44eeda042b5555fbd30a36f98ab425780c8d692eb", 
    "Volumes": { 
     "/data": {} 
    }, 
    "WorkingDir": "", 
    "Entrypoint": [ 
     "/bin/start" 
    ], 
    "NetworkDisabled": false, 
    "OnBuild": [ 
     "ADD ./config /config/" 
    ] 
    }, 
    "architecture": "amd64", 
    "os": "linux", 
    "Size": 0 
} 

Il file layer.tar sembra essere vuota. Così ispezionato il genitore e il nonno, entrambi non contenevano file nei loro file layer.tar.

Quindi supponendo che 4.0K è la dimensione standard per un archivio vuoto:

for layer in $(du -hs */layer.tar | grep -v 4.0K | cut -f2) 
do (echo $layer:;tar tvf $layer) 
done 

vedere che questi contengono semplici modifiche incrementali al file system.

Quindi una conclusione è che probabilmente è meglio usare semplicemente Docker per costruire l'immagine e inserirla nel registro, proprio come fa Packer.

Il modo di creare un'immagine da zero è described in the docs.

Si scopre che docker import - scratch non si cura di cosa c'è nel tarball. Suppongo semplicemente che sia rootfs.

> touch foo 
> tar c foo | docker import - scratch 
02bb6cd70aa2c9fbaba37c8031c7412272d804d50b2ec608e14db054fc0b9fab 
> docker save 02bb6cd70aa2c9fbaba37c8031c7412272d804d50b2ec608e14db054fc0b9fab | tar x 
> ls 02bb6cd70aa2c9fbaba37c8031c7412272d804d50b2ec608e14db054fc0b9fab/ 
VERSION json layer.tar 
> tar tvf 02bb6cd70aa2c9fbaba37c8031c7412272d804d50b2ec608e14db054fc0b9fab/layer.tar  
drwxr-xr-x 0/0    0 2014-09-01 13:46 ./ 
-rw-r--r-- 500/500   0 2014-09-01 13:46 foo 

In termini di integrazione OpenEmbedded, è probabilmente meglio per costruire il rootfs tarball, che è qualcosa Yocto fornisce fuori dalla scatola, e utilizzare il official Python library per importare le rootfs tarball con import_image(src='rootfs.tar', repository='scratch') e spingerlo metodo registro privato .

Questa non è la soluzione più elegante, ma è così che dovrebbe funzionare al momento. Altrimenti si può semplicemente gestire e distribuire le revisioni rootfs a modo loro, e usare semplicemente docker import sull'host di destinazione, che comunque non sarà un buon adattamento, ma è piuttosto semplice.

4

Il formato di immagine Docker è specificato qui: https://github.com/docker/docker/blob/master/image/spec/v1.md

L'immagine più semplice possibile è un file tar contenente quanto segue:

repositories 
uniqid/VERSION 
uniqid/json 
uniqid/layer.tar 

Dove versione contiene 1.0, layer.tar contiene il contenuto chroot e JSON/I repository sono file JSON come specificato nelle specifiche sopra.

Il tar risultante può essere caricato nella finestra mobile tramite docker load < image.tar

Problemi correlati