Você não possui conceitos básicos do Docker. É uma coisa completamente diferente.
A primeira coisa que você precisa saber é a filosofia do Docker: executar um processo isolado em um contêiner. Você não executará um sistema operacional em um contêiner Docker; você executará um processo dentro de um contêiner com um conteúdo de sistema de arquivos raiz baseado em uma distribuição Linux de sua escolha. O Ubuntu é uma escolha entre outros.
Agora você deve se perguntar como é possível obter um processo dentro de uma imagem base do Linux diferente da distribuição Linux com a qual seu host está rodando. Para um sistema operacional funcionar, você basicamente precisa:
- Um sistema de arquivos de inicialização: contém o carregador de inicialização e o kernel que residirão na memória, uma vez carregados. Não nos importamos com isso no caso de contêineres do Docker porque o kernel é compartilhado com o host e é a parte comum entre todas as distribuições do Linux.
- Um sistema de arquivos raiz: contém a estrutura do sistema de arquivos. Pode ser diferente de uma distribuição de 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 acumulá-los.
Nos bastidores, ele usa uma montagem de união que permite que vários sistemas de arquivos sejam montados ao mesmo tempo, aparecendo como um todo virtual. Na verdade, a camada de imagem de base é descartada como modo de leitura / gravação no topo do sistema de arquivos raiz raiz no modo somente leitura.
Aqui você tem uma pilha de blocos de disco em camadas de uma maneira que a distribuição de Linux da qual a imagem base vem conteria o mesmo sistema de arquivos, uma vez instalado em um host real, mas dentro de um contêiner desta vez.
A última coisa que falta agora é: como você controla essa coisa isolada?
A resposta é: namespaces. Eu não vou entrar nos detalhes aqui porque isso iria desviar um pouco da questão original. Mas o que você precisa saber é que desde o kernel 2.4.19, namespaces de vários tipos surgiram ao longo dos anos. Atualmente, os seguintes namespaces estão disponíveis:
- IPC: namespace do IPC (comunicações entre processos)
- MNT: espaço de nomes de montagem
- NET: namespace de rede
- PID: namespace pid
- USER: namespace de usuário (uid)
- UTS: UTS namespace (hostnames)
Namespaces 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 que um processo seja executado nas especificidades do sistema de arquivos raiz da imagem base. O namespace NET será outro recurso importante para que um contêiner tenha interfaces de rede específicas para se comunicar com a ponte de encaixe, etc.
Então, sim, o principal objetivo de tudo isso é executar um aplicativo isolado, enviá-lo de seu ambiente local para a produção com facilidade dentro de uma caixa chamada container.
Seria uma boa ideia ler a documentação do docker antes de aprofundar o assunto.