github.com/drud/ddev@v1.21.5-alpha1.0.20230226034409-94fcc4b94453/docs/content/users/extend/customizing-images.md (about)

     1  # Customizing Docker Images
     2  
     3  It’s common to have a requirement for the `web` or `db` images which isn’t bundled with them by default. There are two ways to extend these Docker images:
     4  
     5  1. `webimage_extra_packages` and `dbimage_extra_packages` in `.ddev/config.yaml`.
     6  2. An add-on Dockerfile in your project’s `.ddev/web-build` or `.ddev/db-build`.
     7  
     8  ## Adding Extra Debian Packages with `webimage_extra_packages` and `dbimage_extra_packages`
     9  
    10  You can add extra Debian packages with lines like this in `.ddev/config.yaml`:
    11  
    12  ```yaml
    13  webimage_extra_packages: [php-yaml, php8.2-tidy]
    14  dbimage_extra_packages: [telnet, netcat]
    15  ```
    16  
    17  Then the additional packages will be built into the containers during [`ddev start`](../usage/commands.md#start).
    18  
    19  ## Determining What Packages You Need
    20  
    21  The `web` container is a Debian image, and its PHP distributions are packaged (thank you!) by [`deb.sury.org`](https://deb.sury.org/).
    22  
    23  Most PHP extensions are built in the `deb.sury.org` distribution. You can Google the extension you want, or download and search the [Packages](https://packages.sury.org/php/dists/buster/main/binary-amd64/Packages) list from the `sury` distribution. For example, the `bcmath` PHP extension is provided by `php-bcmath`. Many packages have version-specific names, like `php7.3-tidy`.
    24  
    25  If you need a package that is *not* a PHP package, you can view and search standard Debian packages at [packages.debian.org/stable](https://packages.debian.org/stable/), or just use Google.
    26  
    27  To test that a package will do what you want, you can [`ddev ssh`](../usage/commands.md#ssh) and `sudo apt-get update && sudo apt-get install <package>` to verify that you can install it and you get what you need. A PHP extension may require `killall -USR2 php-fpm` to take effect. After you’ve tried that, you can add the package to [`webimage_extra_packages`](../configuration/config.md#webimage_extra_packages).
    28  
    29  ## Adding Extra Dockerfiles for `webimage` and `dbimage`
    30  
    31  For more complex requirements, you can add:
    32  
    33  * `.ddev/web-build/Dockerfile`
    34  * `.ddev/web-build/Dockerfile.*`
    35  * `.ddev/db-build/Dockerfile`
    36  * `.ddev/db-build/Dockerfile.*`
    37  
    38  These files’ content will be inserted into the constructed Dockerfile for each image. They are inserted *after* most of the rest of the things that are done to build the image, and are done in alphabetical order, so `Dockerfile` is inserted first, followed by `Dockerfile.*` in alphabetical order.
    39  
    40  For certain use cases, you might need to add directives very early on the Dockerfile like proxy settings or SSL termination. You can use `pre.` variants for this that are inserted *before* everything else:
    41  
    42  * `.ddev/web-build/pre.Dockerfile.*`
    43  * `.ddev/db-build/pre.Dockerfile.*`
    44  
    45  Examine the resultant generated Dockerfile (which you will never edit directly), at `.ddev/.webimageBuild/Dockerfile`. You can force a rebuild with [`ddev debug refresh`](../usage/commands.md#debug-refresh).
    46  
    47  Examples of possible Dockerfiles are `.ddev/web-build/Dockerfile.example` and `.ddev/db-build/Dockerfile.example`, created in your project when you run [`ddev config`](../usage/commands.md#config).
    48  
    49  You can use the `.ddev/*-build` directory as the Docker “context” directory as well. So for example, if a file named `README.txt` exists in `.ddev/web-build`, you can use `ADD README.txt /` in the Dockerfile.
    50  
    51  An example web image `.ddev/web-build/Dockerfile` might be:
    52  
    53  ```dockerfile
    54  RUN npm install -g gatsby-cli
    55  ```
    56  
    57  Another example would be installing `phpcs` globally (see [Stack Overflow answer](https://stackoverflow.com/questions/61870801/add-global-phpcs-and-drupal-coder-to-ddev-in-custom-dockerfile/61870802#61870802)):
    58  
    59  ```dockerfile
    60  ENV COMPOSER_HOME=/usr/local/composer
    61  
    62  # We try to avoid relying on Composer to download global, so in `phpcs` case we can use the PHAR.
    63  RUN curl -L https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar -o /usr/local/bin/phpcs && chmod +x /usr/local/bin/phpcs
    64  RUN curl -L https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.phar -o /usr/local/bin/phpcbf && chmod +x /usr/local/bin/phpcbf
    65  
    66  # If however we need to download a package, we use `cgr` for that.
    67  RUN composer global require consolidation/cgr
    68  RUN $COMPOSER_HOME/vendor/bin/cgr drupal/coder:^8.3.1
    69  RUN $COMPOSER_HOME/vendor/bin/cgr dealerdirect/phpcodesniffer-composer-installer
    70  
    71  # Register Drupal’s code sniffer rules.
    72  RUN phpcs --config-set installed_paths $COMPOSER_HOME/global/drupal/coder/vendor/drupal/coder/coder_sniffer --verbose
    73  # Make Codesniffer config file writable for ordinary users in container.
    74  RUN chmod 666 /usr/local/bin/CodeSniffer.conf
    75  # Make `COMPOSER_HOME` writable if regular users need to use it.
    76  RUN chmod -R ugo+rw $COMPOSER_HOME
    77  # Now turn it off, because ordinary users will want to be using the default.
    78  ENV COMPOSER_HOME=""
    79  ```
    80  
    81  **Remember that the Dockerfile is normally building a Docker image that will be used later with DDEV.** At the time the Dockerfile is executing, your code by default is not mounted and the container is not running, it’s just being built. So for example, an `npm install` in `/var/www/html` will not do anything useful because the code is not there at image building time. However, you use `RUN` in the context of your codebase using something like `RUN --mount=type=bind,source=.,target=/var/www/html cp /var/www/html/index.php /var/tmp/` would mount your code and make it available at the normal `/var/www/html` mount. However, you can't make changes to the mounted code, so things like an early `npm install` wouldn't work, although `npm install -g` would work.
    82  
    83  ### Build Time Environment Variables
    84  
    85  The following environment variables are available for the web Dockerfile to use at build time:
    86  
    87  * `$BASE_IMAGE`: the base image, like `drud/ddev-webserver:v1.21.4`
    88  * `$username`: the username inferred from your host-side username
    89  * `$uid`: the user ID inferred from your host-side user ID
    90  * `$gid`: the group ID inferred from your host-side group ID
    91  * `$DDEV_PHP_VERSION`: the PHP version declared in your project configuration (provided in versions after v1.21.4)
    92  
    93  For example, a Dockerfile might want to build an extension for the configured PHP version like this:
    94  
    95  ```Dockerfile
    96  ENV extension=xhprof
    97  ENV extension_repo=https://github.com/longxinH/xhprof
    98  ENV extension_version=v2.3.8
    99  # For versions <= DDEV v1.21.4 you must also declare DDEV_PHP_VERSION yourself: ENV DDEV_PHP_VERSION=8.1
   100  
   101  RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::="--force-confnew" --no-install-recommends --no-install-suggests autoconf build-essential libc-dev php-pear php${DDEV_PHP_VERSION}-dev pkg-config zlib1g-dev
   102  RUN mkdir -p /tmp/php-${extension} && cd /tmp/php-${extension} && git clone ${extension_repo} .
   103  WORKDIR /tmp/php-${extension}/extension
   104  RUN git checkout ${extension_version}
   105  RUN phpize
   106  RUN ./configure
   107  RUN make install
   108  RUN echo "extension=${extension}.so" > /etc/php/${DDEV_PHP_VERSION}/mods-available/${extension}.ini
   109  ```
   110  
   111  ### Debugging the Dockerfile Build
   112  
   113  It can be complicated to figure out what’s going on when building a Dockerfile, and even more complicated when you’re seeing it go by as part of [`ddev start`](../usage/commands.md#start).
   114  
   115  1. Use [`ddev ssh`](../usage/commands.md#ssh) first of all to pioneer the steps you want to take. You can do all the things you need to do there and see if it works. If you’re doing something that affects PHP, you may need to `sudo killall -USR2 php-fpm` for it to take effect.
   116  2. Put the steps you pioneered into `.ddev/web-build/Dockerfile` as above.
   117  3. If you can’t figure out what’s failing or why, then `~/.ddev/bin/docker-compose -f .ddev/.ddev-docker-compose-full.yaml build web --no-cache --progress=plain` to see what’s happening during the Dockerfile build.