<!--
  canonical-url: https://www.avonture.be/fr/blog/docker-init
  published:     2023-12-07
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Docker init supporte maintenant PHP

> Containerisez votre application PHP rapidement ! Ce guide vous montre comment utiliser la nouvelle fonctionnalité docker init avec PHP et Apache, avec une explication des fichiers Dockerfile et compose.yaml générés.

---
![Docker init supporte maintenant PHP](/img/v2/docker_init.webp)

**TL;DR**

Cet article teste le nouveau template PHP+Apache de `docker init` livré avec Docker Desktop 4.26, qui génère un `Dockerfile`, un `compose.yaml` et un `.dockerignore` via un assistant interactif. On y voit un bug de cette première version (l'instruction `COPY` n'avait pas son chemin source) et pourquoi `.dockerignore` empêche la plupart des fichiers locaux de se retrouver dans l'image construite.

Quelle heureuse et étrange coïncidence. Dans sa nouvelle version (4.26) sortie hier *(le jour de mon anniversaire)*, Docker ajoute le support de **PHP avec Apache** à son instruction `docker init`. Voyons ce que ça donne dans un cas pratique.

> L'article officiel : <https://www.docker.com/blog/docker-desktop-4-26/>

> **Caution:**
>
> On va essayer mais, spoiler, c'est encore très jeune.

Démarrez un shell Linux et lancez `mkdir -p /tmp/docker-init && cd $_` pour créer un dossier `docker-init` dans votre dossier temporaire Linux et vous y placer.

Maintenant, dans votre console, lancez simplement `docker init` et suivez l'assistant.

```bash
$ docker init

Welcome to the Docker Init CLI!

This utility will walk you through creating the following files with sensible defaults for your project:
  \- .dockerignore
  \- Dockerfile
  \- compose.yaml
  \- README.Docker.md

Let's get started!

? What application platform does your project use?  [Use arrows to move, type to filter]
  Go - suitable for a Go server application
  Python - suitable for a Python server application
  Node - suitable for a Node server application
  Rust - suitable for a Rust server application
  ASP.NET Core - suitable for an ASP.NET Core application
\> PHP with Apache - suitable for a PHP web application
  Other - general purpose starting point for containerizing your application
  Don't see something you need? Let us know!
  Quit
```

Veillez à sélectionner `PHP with Apache - suitable for a PHP web application`.

Pour les questions suivantes :

* `What version of PHP do you want to use?`, entrez par exemple `8.2`,
* `What's the relative directory for your app?`, appuyez simplement sur Entrée pour sélectionner le dossier courant,
* `What local port do you want to use to access your server?`, appuyez sur Entrée pour utiliser le port proposé ou entrez par exemple `8080`.

```bash
? What application platform does your project use? PHP with Apache
? What version of PHP do you want to use? 8.2
? What's the relative directory (with a leading .) for your app?
? What local port do you want to use to access your server? 8080

CREATED: .dockerignore
CREATED: Dockerfile
CREATED: compose.yaml
CREATED: README.Docker.md

✔ Your Docker files are ready!

Take a moment to review them and tailor them to your application.

If your application requires specific PHP extensions, you can follow the instructions in the Dockerfile to add them.

When you're ready, start your application by running: docker compose up --build

Your application will be available at http://localhost:8080

Consult README.Docker.md for more information about using the generated files.
```

L'assistant est plutôt direct et, au final, on obtient quatre fichiers.

Deux sont vraiment importants pour l'instant : `compose.yaml` et `Dockerfile`.

## compose.yaml {#composeyaml}

En ouvrant `compose.yaml` avec Visual Studio Code, vous verrez beaucoup de commentaires.

Par défaut, tout est commenté sauf :

**compose.yaml**

```yaml
services:
  server:
    build:
      context: .
    ports:
      - 8080:80
```

Ok, ça veut simplement dire qu'on n'utilisera pas une image Docker standard, déjà existante, mais qu'on va construire la vôtre et que la définition de cette image se trouve dans le dossier courant (`context: .`). La définition de votre image Docker doit être écrite dans le fichier standard `Dockerfile`.

La deuxième chose qu'on voit ici, c'est le numéro de port choisi. Le container Docker sera publié sur le port 8080.

## Dockerfile {#dockerfile}

Ici aussi, `docker init` a créé un fichier avec beaucoup de commentaires. Si on les retire, voici les lignes non commentées :

**Dockerfile**

```docker
FROM php:8.2-apache
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY . /var/www/html
USER www-data
```

> **Bug dans Docker 4.26 - Docker init - PHP + Apache:**
>
> Il y a un bug dans la release `4.26` : l'instruction `COPY` doit être `COPY . /var/www/html` (autrement dit, il faut préciser le dossier source `.`). J'ai créé une issue sur le repository Docker (<https://github.com/docker/cli/issues/4702>)
>
> Mettez à jour le fichier `Dockerfile` et remplacez la ligne `COPY /var/www/html` par `COPY . /var/www/html`

On voit donc qu'on va utiliser l'image `php:8.2-apache` (puisqu'on a demandé PHP `8.2`), qu'on va copier le contenu de votre dossier courant (`.`) vers le dossier `/var/www/html` dans l'image Docker, qu'on va aussi utiliser le fichier `php.ini` de production (voyez [Update php.ini when using a Docker image](/blog/docker-php-ini) si vous devez l'ajuster) et qu'on va basculer l'utilisateur Linux courant dans le container vers `www-data`.

## Lancer le container {#run-the-container}

Ok, rien de bien compliqué jusqu'ici. On va créer l'image en lançant `docker compose up --build`.

Une fois construite, on peut surfer sur `http://localhost:`8080 et ... aïe.

> Screenshot — http\://localhost:8080
>
> ![Forbidden](./images/forbidden.webp)

**Et c'est tout à fait normal.** Rappelez-vous, votre dossier courant ne contient pour l'instant que les quatre fichiers créés par `docker init`.

Créez le fichier `index.php` avec ce contenu :

**index.php**

```php
<?php

phpinfo();
```

Retournez dans votre console, appuyez sur `CTRL`-`C` pour arrêter le premier container et lancez cette fois `docker compose up --detach --build` (comme ça la console ne sera pas bloquée et le container tournera en arrière-plan).

> Screenshot — http\://localhost:8080
>
> ![phpinfo](./images/phpinfo.webp)

## Entrer dans le container {#enter-in-the-container}

On va démarrer un shell interactif dans le container. Il suffit de savoir comment le container est nommé.

Retour au fichier `compose.yaml` : on y retrouve le nom du container ; c'est le nom du service, `server` dans ce cas.

**compose.yaml**

```yaml
services:
  # highlight-next-line
  server:
    [...]
```

Pour lancer un shell interactif, exécutez la commande suivante :

```bash
$ docker compose exec server /bin/bash
www-data@86e3fd14ea18:~/html$
```

Comme prévu, vous êtes maintenant dans le container. Vous pouvez afficher la liste des fichiers en lançant `ls -alh`

```bash
$ www-data@86e3fd14ea18:~/html$ ls -alh
total 20K
drwxrwxrwt 1 www-data www-data 4.0K Dec  7 17:52 .
drwxr-xr-x 1 root     root     4.0K Nov 21 17:46 ..
-rw-r--r-- 1 root     root      742 Dec  7 17:34 README.Docker.md
-rw-r--r-- 1 root     root       17 Dec  7 17:49 index.php
```

Donc, même si votre dossier courant, sur votre machine, contient maintenant cinq fichiers, seuls `README.Docker.md` et `index.php` sont présents. Pourquoi pas les autres ?

## .dockerignore {#dockerignore}

Sur votre machine, on a donc cinq fichiers :

```bash
$ ls -alh
total 36K
drwxr-xr-x  2 christophe christophe 4.0K Dec  7 17:59 .
drwxrwxrwt 32 root       root        12K Dec  7 17:59 ..
-rw-r--r--  1 christophe christophe  646 Dec  7 17:34 .dockerignore
-rw-r--r--  1 christophe christophe 2.3K Dec  7 17:03 Dockerfile
-rw-r--r--  1 christophe christophe  742 Dec  7 17:34 README.Docker.md
-rw-r--r--  1 christophe christophe 1.7K Dec  7 17:34 compose.yaml
-rw-r--r--  1 christophe christophe   17 Dec  7 17:49 index.php
```

Et seuls `README.Docker.md` et `index.php` ont été copiés dans le container.

La raison : les autres fichiers ont été ignorés parce qu'ils sont mentionnés dans le fichier `.dockerignore`.

**.dockerignore**

```
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/

**/.classpath
//highlight-next-line
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.next
**/.cache
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
//highlight-next-line
**/compose*
!**/composer.json
!**/composer.lock
//highlight-next-line
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
**/vendor
LICENSE
README.md
```

Nous voilà à la fin de cet article. On a utilisé l'instruction `docker init` pour créer le strict minimum nécessaire à l'exécution d'un script PHP dans un container Apache.

*Si tout ce que vous voulez, c'est lancer un script rapidement, sans aucun fichier généré, [The easiest way to run a PHP script / website](/blog/docker-php-run-script-or-website) tient en une seule ligne.*

Dans les prochains mois, je garderai un œil sur l'évolution de `docker init` du côté de PHP.
