Mantendo o ENTRYPOINT e o CMD originais de uma imagem Docker gerada através do Packer
Tags: devops, sre, docker, packer
Published: 2021-09-23 21:19:44

Imagine o seguinte cenário: existe uma imagem Docker que faz *quase-tudo* que você precisa, mas falta alguma coisinha, um pacote, um arquivinho, um *redirect*. Logo, o que você faz? Cria um `Dockerfile`, utiliza aquela imagem como base em um `FROM`, executa meia dúzia de `RUN`, `COPY`, e cria uma imagem nova, adiciona uma *tag* e pronto. Problema resolvido, certo?

Uma outra possibilidade é utilizar o [Packer](https://www.packer.io) para gerar a imagem. Ele, diferente do Docker, não utilizará um arquivo `Dockerfile`, mas gerará a nova imagem provisionando um *container*, fazendo as coisas que tem que fazer lá dentro e quando tudo estiver pronto, ele executará um *commit*, criando assim uma nova imagem.

Se você optou pelo segundo método, pode ter se frustrado no momento de executar um *container* baseado na segunda imagem. Um serviço não subiu, o *container* não fez o que ele deveria ter feito, e você ficou com uma cara de "ué". 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pf50tt1qj54knlh61pwk.png)

O motivo disso é que, diferentemente de um `Dockerfile`, o Packer não faz com que a nova imagem herde o ENTRYPOINT e o CMD da imagem base. Para contornar esse comportamento do Packer, escreva o seu arquivo de *template* da seguinte forma:

```hcl
source "docker" "my-jenkins" {
    image = "jenkins/jenkins:lts-jdk11"
    commit = true
    run_command = ["-d", "-i", "-t", "--", "{{.Image}}"]
    changes = [
        "ENTRYPOINT /sbin/tini -- /usr/local/bin/jenkins.sh",
        "CMD bash"
    ]
    exec_user = "root"
}

build {
    sources = [
        "source.docker.my-jenkins"
    ]
    provisioner "shell" {
        inline = [
            "apt update",
            "apt install -y htop"
        ]
    }
    post-processor "docker-tag" {
        repository = "my-jenkins"
    }
}
```

Neste exemplo, nós estamos criando uma nova imagem do Jenkins com o pacote **htop**, utilizando a imagem base do mesmo. Para isso, fizemos o seguinte:

- `run_command`: opções utilizados pelo Packer ao inicializar o *container* que gerará a imagem. Por padrão, há uma opção `--entrypoint=/bin/sh`, que nós estamos removendo;

- `changes`: esta é a parte mais importante. Precisamos restaurar o ENTRYPOINT e o CMD originais da imagem, e para isso, vá até a página da mesma no [Docker Hub](https://hub.docker.com) e verifique-os consultando o `Dockerfile` da mesma;

- `exec_user`: o usuário utilizado (UID) para executar o *provisioner* da imagem. Um *provisioner* é a parte do *template* responsável pela instalação dos pacotes, arquivos, etc. Como estamos instalando um novo pacote através do `apt`, precisamos que esse comando seja executado como root;

Ao final, estamos colocando a *tag* **my-jenkins** na imagem por meio do *post-processor* `docker-tag`.

## Conclusão

Embora muitas pessoas ainda utilizem Dockerfiles para a construção de suas imagens - e não há nada de errado nisso - o Packer é uma opção interessante e que pode nos auxiliar a fazer o mesmo. O intuito deste artigo não é o apresentar como tal, mas sim resolver um problema comum que provavelmente afetará as pessoas que escolheram tal caminho.