Skip to content
This repository has been archived by the owner on Jan 13, 2023. It is now read-only.

Build instructions for how to bootstrap and maintain Drupal 8 codebase + container #111

Closed
geerlingguy opened this issue Jun 9, 2018 · 23 comments

Comments

@geerlingguy
Copy link
Owner

So here's where a lot of the rubber meets the road...

  1. In Build initial Drupal 8 codebase if not present #104, I made things work out of the box with a freshly-downloaded-if-not-present Drupal 8 codebase using the geerlingguy/drupal image from Docker Hub.
  2. In Deploy a local Docker registry inside Kubernetes cluster #108, I'm working on adding a private Docker registry to the cluster.
  3. There are tons of ways of bootstrapping a new Drupal codebase for a new Drupal site; I like either tarball download or drupal-project if I need more modules and Composery delights.
  4. Very little documentation exists around the web of an actual, "go-to-prod" container build workflow where you have a Drupal codebase, and production (and/or other environments), and you build a container with all the code inside, and you push it to production.

99.9% of all the blog posts, docs, etc., assume you're just mounting the codebase inside the container using a Docker volume / bind mount / etc.

But I want to document (and start using in my personal infra, quite frankly!) a process whereby:

  1. Every commit to master builds a new production-ready Docker container image.
  2. The container image can be automagically deployed up to the production environment using Kubernetes (update the spec.template.spec.containers[0].image in the drupal8.yml manifest to point to the new tagged image or latest hash).

I might not go the full distance and automate everything 100% inside this project's codebase; but I do want that workflow to be enabled easily, and I want at least one or more of the following:

  • Documentation of exactly how to do it the right way.
  • An Ansible playbook that does the container build, tagging, push to private repo, and kubectl apply of the changed image.
@geerlingguy
Copy link
Owner Author

geerlingguy commented Jun 9, 2018

One quick question I want to jot here while it's on my mind:

Is it possible (if so, how?) to make a truly cumalative git-repo-based container image where new tags/hashes/versions only contain a new layer with the changes from the latest git hash (rather than each new container image containing the entire codebase as a layer, meaning every image will be at least as big as the size of the codebase)?

I know that was one of the whiz-bang intro-to-Docker-101 level things I remember hearing about... but in practice most places seem to add a COPY [codebase] [container path] and that generates a new image with a unique layer with the entire codebase.

For a lot of poorly-architected codebases (I've seen them in the 1-5 GB range!), that means giant blobs of images for every single commit, ever!

@geerlingguy
Copy link
Owner Author

#108 is complete, so we have a local private Docker registry with which images can be managed locally.

@geerlingguy
Copy link
Owner Author

The main thing that's annoying—if you do a kubectl delete pod [drupal8 pod here], it brings a new one up, and every time that happens you have to re-run the Drupal installer so the settings.php file knows the database credentials.

Would like to make it so the settings.php can be dynamically generated, or gets info from environment variables (the latter seems better, and the vars for DB connection are already there).

@geerlingguy
Copy link
Owner Author

Working on geerlingguy/drupal-container#12 as a stop-gap, to hopefully allow multiple replicas of the Drupal container to run and use the same database connection and not do... weird things.

@geerlingguy
Copy link
Owner Author

I think the approach I'm going to take is:

  • Use geerlingguy/drupal container by default, for testing, etc.
  • Use the new Drupal Example for Kubernetes site to show people how to build a Drupal project worthy of deployment into a Kubernetes cluster.

Also going to move #133 into that project's repo, since it literally contains all the contents of the Pi Dramble website now (yay!). And soon I'll also need to install that site on the running cluster/Pi itself and finally step away from Bartik :)

@geerlingguy
Copy link
Owner Author

geerlingguy commented Feb 16, 2019

Just a scratchpad for potential changes to make the Drupal Example for Kubernetes to work as a drop-in swap for the current container:

DRUPAL_DATABASE_HOST: 'mysql'
DRUPAL_DATABASE_PORT: '3306'
DRUPAL_DATABASE_NAME: 'drupal'
DRUPAL_DATABASE_USERNAME: 'drupal'
DRUPAL_HASH_SALT: '{{ drupal_hash_salt }}'
DRUPAL_DATABASE_PASSWORD: [secret]

drupal-files NFS volume mount is at path /var/www/html/sites/default/files—might need to make that a variable so I can set it to /var/www/html/web/sites/default/files instead. (Edit: Added var drupal_files_dir).

I also will need to make the FROM allow for an ARG (https://www.jeffgeerling.com/blog/2017/use-arg-dockerfile-dynamic-image-specification), so I can use the base image geerlingguy/drupal:latest-arm32v7 when building for ARM.

@geerlingguy
Copy link
Owner Author

To get the registry working correctly, I'm going to need to knock out #114 as well...

@geerlingguy
Copy link
Owner Author

geerlingguy commented Feb 17, 2019

Registry is working correctly now. So next steps (jotting since I'm folding up shop for the night):

  • Maybe rename k8s-cert-setup.yml to k8s-registry-cert-setup.yml and use it for the below tasks?
  • Add task(s) / include(s) to:
    • Add registry.pidramble.test hosts entry to /etc/hosts on all Pis, pointing at the IP address of kube3 (e.g. 192.168.77.4 for Vagrant).
    • Add tls.crt file to cert store on all Pis (copy to /etc/docker/certs.d/{{ docker_registry_domain }}/ca.crt) (see docs for this).
  • Set drupal_docker_image and drupal_files_dir to use Drupal Example for Kubernetes
  • Deploy manifest and see if the image gets pulled... even better, see if I can install Drupal!
  • Work on doing all of the stuff on the Pis (including the ARG addition for FROM as mentioned earlier).

@geerlingguy
Copy link
Owner Author

Looks like I'll have to do a few more things to the Drupal for Kubernetes project to get it fully ready to run in the Kubernetes environment... getting:

[Sun Feb 17 19:09:39.644065 2019] [php7:notice] [pid 10] [client 10.244.2.0:45648] Drupal\\Core\\Database\\DatabaseAccessDeniedException: SQLSTATE[HY000] [1045] Access denied for user 'drupal'@'10.244.1.9' (using password: YES) in /var/www/html/web/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php on line 427 #0 /var/www/html/web/core/lib/Drupal/Core/Database/Database.php(371): Drupal\\Core\\Database\\Driver\\mysql\\Connection::open(Array)\n#1 /var/www/html/web/core/lib/Drupal/Core/Database/Database.php(166): Drupal\\Core\\Database\\Database::openConnection('default', 'default')\n#2 [internal function]: Drupal\\Core\\Database\\Database::getConnection('default')\n#3 /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php(79): call_user_func_array('Drupal\\\\Core\\\\Dat...', Array)\n#4 /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php(171): Drupal\\Component\\DependencyInjection\\PhpArrayContainer->createService(Array, 'database')\n#5 /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php(260): Drupal\\Component\\DependencyInjection\\Container->get('database', 1)\n#6 /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php(62): Drupal\\Component\\DependencyInjection\\PhpArrayContainer->resolveServicesAndParameters(Array)\n#7 /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php(171): Drupal\\Component\\DependencyInjection\\PhpArrayContainer->createService(Array, 'cache.container')\n#8 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(543): Drupal\\Component\\DependencyInjection\\Container->get('cache.container')\n#9 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(904): Drupal\\Core\\DrupalKernel->getCachedContainerDefinition()\n#10 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(476): Drupal\\Core\\DrupalKernel->initializeContainer()\n#11 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(692): Drupal\\Core\\DrupalKernel->boot()\n#12 /var/www/html/web/index.php(19): Drupal\\Core\\DrupalKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request))\n#13 {main}

@geerlingguy
Copy link
Owner Author

geerlingguy commented Feb 17, 2019

I had to manually edit settings.php:

$config_directories['sync'] = '../config/sync';
$databases['default']['default'] = array (
  'database' => getenv('DRUPAL_DATABASE_NAME'),
  'username' => getenv('DRUPAL_DATABASE_USERNAME'),
  'password' => getenv('DRUPAL_DATABASE_PASSWORD'),
  'prefix' => '',
  'host' => getenv('DRUPAL_DATABASE_HOST'),
  'port' => '',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
);
$settings['hash_salt'] = getenv('DRUPAL_HASH_SALT');

Then I had to drop all tables and reinstall Drupal:

$ vendor/bin/drush sql-drop -y
$ vendor/bin/drush site:install minimal --db-url="mysql://drupal:$DRUPAL_DATABASE_PASSWORD@$DRUPAL_DATABASE_HOST/drupal" --site-name="Drupal Example Site for Kubernetes" --existing-config -y

@geerlingguy
Copy link
Owner Author

Milestone: I have Drupal for Kubernetes running on the cluster:

site-on-local-cluster

But I need to fix the settings.php situation so I can install-if-not-installed and have it automatically start if already installed (without messing up settings or having the wrong settings).

I thought I had already figured this out elsewhere, but I'm not seeing where I did so :/

@geerlingguy
Copy link
Owner Author

Ah... I did set this up over in the drupal-container repo: https://github.com/geerlingguy/drupal-container/blob/master/docker-entrypoint.sh#L27-L42

Problem is, that's only run for the downloaded Drupal tarball, not for the Drupal for Kubernetes codebase! So I'll need to create a template settings.php or something like that for use in production.

@geerlingguy
Copy link
Owner Author

Fixed over in geerlingguy/drupal-for-kubernetes#10 — local testing is good so far!

Next up, I need to start testing this on the real Pi cluster... and test building the image on ARM32 (right now I've only tested on AMD64).

@geerlingguy
Copy link
Owner Author

Installing on a freshly-reset set of Pis now. Apparently Docker 18.09.2 has not yet been released for Raspbian:

E: Version '5:18.09.2~3-0~raspbian-stretch' for 'docker-ce' was not found

So I have to stick to 5:18.09.0~3-0~raspbian-stretch for now :-/

(See:
https://download.docker.com/linux/raspbian/dists/stretch/stable/binary-armhf/Packages)

@geerlingguy
Copy link
Owner Author

Weird, now I'm running into:

$ kubectl exec -n drupal $DRUPAL_POD -- bash -c 'vendor/
bin/drush site:install minimal --db-url="mysql://drupal:$DRUPAL_DATABASE_PASSWORD@$DRUPAL_DATABASE_HOST/drupal" --site-name="Drupal Example Site for Kubernetes" --existing-config -y'

 // You are about to DROP all tables in your 'drupal' database. Do you want to  
 // continue?: yes.                                                             

 [notice] Starting Drupal installation. This takes a while.
TypeError: Return value of Doctrine\Common\Annotations\AnnotationRegistry::reset() must be an instance of Doctrine\Common\Annotations\void, none returned in Doctrine\Common\Annotations\AnnotationRegistry::reset() (line 55 of /var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php).
TypeError: Return value of Doctrine\Common\Annotations\AnnotationRegistry::reset() must be an instance of Doctrine\Common\Annotations\void, none returned in /var/www/html/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php on line 55 #0 /var/www/html/web/core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php(113): Doctrine\Common\Annotations\AnnotationRegistry::reset()
#1 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityTypeManager.php(106): Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery->getDefinitions()
#2 /var/www/html/web/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php(175): Drupal\Core\Entity\EntityTypeManager->findDefinitions()
#3 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityManager.php(675): Drupal\Core\Plugin\DefaultPluginManager->getDefinitions()
#4 /var/www/html/web/core/lib/Drupal/Core/Config/ConfigManager.php(100): Drupal\Core\Entity\EntityManager->getDefinitions()
#5 /var/www/html/web/core/lib/Drupal/Core/Config/ConfigInstaller.php(317): Drupal\Core\Config\ConfigManager->getEntityTypeIdByName('core.extension')
#6 /var/www/html/web/core/lib/Drupal/Core/Config/ConfigInstaller.php(132): Drupal\Core\Config\ConfigInstaller->createConfiguration('', Array)
...

@geerlingguy
Copy link
Owner Author

Dangit... apparently this has to do with the PHP 7.0.33 version that is present on the ARM version of geerlingguy/drupal.

I'll have to look at upgrading to 7.1 or later. See: acquia/blt#2660 (comment)

Trying https://getgrav.org/blog/raspberrypi-nginx-php7-dev — but actually considering building/using a buster container as it already has php7.2-* packages available and I wouldn't have to twiddle with apt priorities.

@geerlingguy
Copy link
Owner Author

Could also use one of my favorite repos—apparently Oerdnj supports ARM now, who knew? oerdnj/deb.sury.org#579

@geerlingguy
Copy link
Owner Author

Upstream issue: geerlingguy/drupal-container#17

@geerlingguy
Copy link
Owner Author

PHP 7.3.x/buster did not work out of the box, so trying Ondrej Sury's repos now.

@geerlingguy
Copy link
Owner Author

Still working on these issues through the drupal-for-kubernetes and drupal-container projects...

@geerlingguy
Copy link
Owner Author

Build pipelines are always amazing until there are little failures in multiple stages.

@geerlingguy
Copy link
Owner Author

Fixed the upstream issues, running PHP 7.2.x now, and the site loads from the Pi Cluster just as well as it does from the local Vagrant/VirtualBox cluster, yay!

@geerlingguy
Copy link
Owner Author

I've added all the build directions to the Drupal for Kubernetes repo over here: https://github.com/geerlingguy/drupal-for-kubernetes/tree/master/docs

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant