Building a Custom version of the Plone backend image with our own addon

I'm currenting working on customising the Plone backend image.
The specific use case for me is mounting and building source code.
My strategy is to copy the files over and then build. The docs are not explicit about how to trigger a build that also builds my source code.

I'm currently investigating.

The documentation that I'm reading on extending the Plone docker image seems a bit sparse.

Here's what my Dockerfile looks like so far.

FROM plone/plone-backend:6.0.0b1

COPY src/my.profile /app/src/my.profile
COPY src/my.content /app/src/my.content
COPY src/my.plone /app/src/my.plone
COPY src/my.customviews /app/src/my.customviews

RUN apt-get update \
    && apt-get install -y --no-install-recommends gcc \
    && rm -rf /var/lib/apt/lists/*

Running

docker build .

works! So that's the "hello world" out of the way.
Next I'm looking for what to add to my Dockerfile to trigger a rebuild with my source code.

I'm still living that "buildout life"... so I'm looking into the whole pip/wheelhouse approach. Shopping around for examples (starting from the Dockerfile). plone-backend/Dockerfile at 5.2.x · plone/plone-backend · GitHub

@pigeonflight next you should do pip install.

See plone-backend/docker-entrypoint.sh at 74a3f45085444f07bad789e7af08380c322a6cef · plone/plone-backend · GitHub

Thus:

RUN /app/bin/pip install --editable /app/src/my.profile \
 && /app/bin/pip install --editable /app/src/my.content \
 && /app/bin/pip install --editable /app/src/my.plone \
 && /app/bin/pip install --editable /app/src/my.customviews
1 Like

@avoinea thank you SO MUCH!!!!! :tada:
I'm sure you just saved me a week!

Wasn't even thinking of /app/bin as the path.

1 Like

That worked!
I'm assuming that I can do something similar for third party addons.

RUN /app/bin/pip install collective.easyform \
 && /app/bin/pip install collective.exportimport
1 Like

The build was successful. From this Dockerfile:

FROM plone/plone-backend:6.0.0b1

COPY src/my.profile /app/src/my.profile
COPY src/my.content /app/src/my.content
COPY src/my.plone /app/src/my.plone
COPY src/my.customviews /app/src/my.customviews

RUN apt-get update \
    && apt-get install -y --no-install-recommends gcc \
    && rm -rf /var/lib/apt/lists/*

RUN /app/bin/pip install --editable /app/src/my.profile \
 && /app/bin/pip install --editable /app/src/my.content \
 && /app/bin/pip install --editable /app/src/my.plone \
 && /app/bin/pip install --editable /app/src/my.customviews

RUN /app/bin/pip install collective.easyform \
 && /app/bin/pip install collective.exportimport

Using this command:
docker build . -t mysite

However when I run the following command

docker run -p 8080:8080  -e SITE="Plone" -e TYPE="classic" -e PROFILES="my.profile:default collective.easyform:default"  -v $(pwd)/var/import:/app/import mysite

it fails with the following output:

Creating Plone classic SITE: Plone
Aditional profiles: my.profile:default collective.easyform:default
THIS IS NOT MEANT TO BE USED IN PRODUCTION
Read about it: https://github.com/plone/plone-backend/#extending-from-this-image
=======================================================================================
Traceback (most recent call last):
  File "/app/bin/zconsole", line 8, in <module>
    sys.exit(main())
  File "/app/lib/python3.9/site-packages/Zope2/utilities/zconsole.py", line 50, in main
    runscript(namespace.zopeconf, *namespace.scriptargs)
  File "/app/lib/python3.9/site-packages/Zope2/utilities/zconsole.py", line 13, in runscript
    make_wsgi_app({}, zopeconf)
  File "/app/lib/python3.9/site-packages/Zope2/Startup/run.py", line 61, in make_wsgi_app
    starter.prepare()
  File "/app/lib/python3.9/site-packages/Zope2/Startup/starter.py", line 38, in prepare
    self.startZope()
  File "/app/lib/python3.9/site-packages/Zope2/Startup/starter.py", line 94, in startZope
    Zope2.startup_wsgi()
  File "/app/lib/python3.9/site-packages/Zope2/__init__.py", line 36, in startup_wsgi
    _startup()
  File "/app/lib/python3.9/site-packages/Zope2/App/startup.py", line 70, in startup
    OFS.Application.import_products()
  File "/app/lib/python3.9/site-packages/OFS/Application.py", line 393, in import_products
    import_product(product_dir, product_name)
  File "/app/lib/python3.9/site-packages/OFS/Application.py", line 402, in import_product
    product = __import__("Products.%s" % product_name,
  File "/app/lib/python3.9/site-packages/Products/Archetypes/__init__.py", line 2, in <module>
    import bbb
ModuleNotFoundError: No module named 'bbb'

Note for anyone reading this... I think I need to clean up some dependencies in my source.

@pigeonflight A few tips...

  1. It looks like your latest error is because something is pulling in Archetypes as a dependency. Plone 6 does not support Archetypes, and the specific error is because that import in the Archetypes code is relying on a Python 2 feature that was removed in Python 3 (implicit relative imports)
  2. In general, writing Dockerfiles is a complex topic and it's easy to accidentally create Dockerfiles that create larger images or take more time to run than they need to. I'd recommend taking some time to read about best practices.
  3. Each command in the Dockerfile creates a new layer, and layers are cached if the files that were copied in so far have not changed. So, it's best to put the things that change the least often earlier in the Dockerfile, and then when you build, that part can be skipped. In your example, I would put the apt-get installation of gcc at the top, followed by installing addons, followed by installing your project code.
  4. I would include a version pin for the addons to make sure you don't accidentally get a different version when you build again at a different time.

That's probably enough suggestions for now :slight_smile:

1 Like

Thank you @davisagli all useful pointers.
:white_check_mark: I was able to find some dependencies that I didn't need that were bringing in Archetypes (this project has a history going back to Plone 3 probably)

:white_check_mark: I'll definitely restructure the file based on your suggestions (including version pinning).