Faltam conceitos básicos do Docker. É uma coisa completamente diferente.
A primeira coisa que você precisa saber é a filosofia do Docker: execute um processo isolado em um contêiner. Você não executará um SO em um contêiner do Docker, executará um processo dentro de um contêiner com um conteúdo de sistema de arquivos raiz com base em uma distribuição Linux à sua escolha. O Ubuntu é uma escolha entre outras.
Agora você deve se perguntar como é possível obter um processo executando dentro de uma imagem base linux diferente da distribuição linux com a qual seu host está sendo executado. Para um sistema operacional rodar, você precisa basicamente de:
- Um sistema de arquivos de inicialização: contém o carregador de inicialização e o kernel que residirá na memória após o carregamento. Não nos preocupamos com isso no caso dos contêineres do Docker, porque o kernel é compartilhado com o host e é a parte comum entre todas as distribuições linux.
- Um sistema de arquivos raiz: contém a estrutura do sistema de arquivos. Pode ser diferente de uma distribuição Linux para outra. É somente leitura até a sequência de inicialização terminar.
O Docker usa o UnionFS para gerenciar camadas de blocos de disco dentro de um contêiner, para que você possa empilhá-los.
Nos bastidores, ele usa um suporte de união que permite que vários sistemas de arquivos sejam montados ao mesmo tempo, parecendo um sistema virtual inteiro. De fato, descarta a camada de imagem base como modo de leitura e gravação no topo do sistema de arquivos raiz básico no modo somente leitura.
Aqui você tem uma pilha de blocos de disco em camadas de uma maneira que a distribuição linux da qual a imagem base vem conteria o mesmo sistema de arquivos uma vez instalado em um host real, mas desta vez dentro de um contêiner.
A última coisa que falta agora é: como você administra essa coisa isolada?
A resposta é: namespaces. Não vou entrar em detalhes aqui, porque isso se desviaria um pouco da pergunta original. Mas o que você precisa saber é que desde o kernel 2.4.19, namespaces de vários tipos apareceram ao longo dos anos. Atualmente, os seguintes namespaces estão disponíveis:
- IPC: espaço de nome IPC (comunicações entre processos)
- MNT: montar espaço para nome
- NET: espaço para nome da rede
- PID: espaço de nome pid
- USER: espaço para nome do usuário (uid)
- UTS: espaço de nome UTS (nomes de host)
Os espaços para nome são estruturas isoladas dentro do kernel que permitem que os processos sejam executados com um ambiente específico. Por exemplo, o namespace MNT será o principal recurso para executar um processo nas especificidades do sistema de arquivos raiz da imagem base. O espaço para nome NET será outro recurso importante para um contêiner ter interfaces de rede específicas para se comunicar com a ponte docker etc.
Portanto, sim, o objetivo principal de tudo isso é executar um aplicativo isolado, enviá-lo do ambiente local para produção facilmente dentro de uma caixa chamada contêiner.
Seria uma boa idéia ler a documentação do docker antes de aprofundar a questão.