Skip to content

Commit e93f417

Browse files
authored
Merge pull request #982 from plone/issue-975
Deployment training 2025
1 parent 9e71be9 commit e93f417

13 files changed

Lines changed: 415 additions & 243 deletions
-114 KB
Binary file not shown.

docs/plone-deployment/_static/request_flow.svg

Lines changed: 67 additions & 0 deletions
Loading

docs/plone-deployment/deploy.md

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This guide outlines the steps to deploy the project using a Docker stack compris
1818
- **Plone Backend:** The API service.
1919
- **Postgres 14 Database:** Handles data persistence.
2020

21-
You can find this stack at {file}`devops/stacks/ploneconf2024-<your-github-username>.tangrama.com.br.yml`. It's modular, allowing easy integration of additional services like {term}`Varnish`, `Solr`, or `ElasticSearch`.
21+
You can find this stack at {file}`devops/stacks/ploneconf2025-<your-github-username>.tangrama.com.br.yml`. It's modular, allowing easy integration of additional services like {term}`Varnish`, `Solr`, or `ElasticSearch`.
2222

2323
```{seealso}
2424
[Traefik Proxy with HTTPS](https://dockerswarm.rocks/traefik/)
@@ -27,7 +27,7 @@ You can find this stack at {file}`devops/stacks/ploneconf2024-<your-github-usern
2727
## Building Docker Images
2828

2929
Ensure you build the Docker images for the Frontend and Backend servers before deployment.
30-
GitHub Actions, configured in {file}`.github/workflows/backend.yml` and {file}`.github/workflows/frontend.yml`, facilitate this process.
30+
GitHub Actions, configured in {file}`.github/workflows/main.yml`, facilitate this process.
3131

3232
````{important}
3333
Before deploying, run the following commands from your project's root directory to format the code and run tests.
@@ -56,43 +56,48 @@ Watch Usage
5656
After these commands succeed, commit all code changes, push to GitHub, and ensure all GitHub Actions successfully complete their runs.
5757
````
5858

59-
60-
## Manual Deployment with `devops/Makefile`
59+
## Manual Deployment with Ansible
6160

6261
Utilize the {file}`Makefile` at {file}`devops/Makefile` for manual deployment.
6362

6463
### Deploying the Stack
6564

66-
Execute the following command from your project's {file}`devops` directory to deploy the stack defined in {file}`devops/stacks/ploneconf2024-<your-github-username>.tangrama.com.br.yml` to the remote server.
65+
Execute the following command from your project's {file}`devops/ansible` directory to deploy the stack defined in {file}`devops/stacks/ploneconf2025-<your-github-username>.tangrama.com.br.yml` to the remote server.
6766

6867
```shell
69-
make stack-deploy
68+
uv run ansible-playbook playbooks/deploy.yml --tags project
7069
```
7170

7271
### Verifying Stack Status
7372

74-
To check the status of all services in your stack, run:
73+
To check the status of all services in your stack, access the remote server:
74+
75+
```shell
76+
ssh root@ploneconf2025-<your-github-username>.tangrama.com.br
77+
```
78+
79+
And then run the command:
7580

7681
```shell
77-
make stack-status
82+
docker stack ps ploneconf2025-<your-github-username>-tangrama-com-br
7883
```
7984

8085
### Creating Plone Site
8186

8287
On the initial deployment, the frontend containers might be unhealthy due to the unconfigured Plone site on the backend. Create a new site with:
8388

8489
```shell
85-
make stack-create-site
90+
docker exec $(docker ps -qf 'name=_backend'|head -n1) ./docker-entrypoint.sh create-site
8691
```
8792

8893
### Monitoring Logs
8994

9095
Monitor the logs of each service with these commands:
9196

92-
- Traefik: `make stack-logs-webserver`
93-
- Frontend: `make stack-logs-frontend`
94-
- Backend: `make stack-logs-backend`
95-
- Backend: `make stack-logs-db`
97+
- Traefik: `docker service logs traefik_traefik --follow`
98+
- Frontend: `docker service logs <stack-name>_frontend --follow`
99+
- Backend: `ocker service logs <stack-name>_backend --follow`
100+
- Database: `ocker service logs <stack-name>_db --follow`
96101

97102
## Automating Deployment with GitHub Actions
98103

@@ -130,15 +135,6 @@ Add secrets in the `Secrets` section of your environment. Refer to the table bel
130135
| DEPLOY_SSH | Content of {file}`devops/etc/keys/plone_prod_deploy_rsa` | The private SSH key for connection. |
131136
| ENV_FILE | Content of {file}`devops/.env_file_gha` | File containing environment variables for the stack file. |
132137

133-
#### Adding Repository Variables
134-
135-
Navigate to {menuselection}`Settings --> Secrets and Variables --> Actions`. Under {guilabel}`Variables`, add the repository variable:
136-
137-
| Name | Value |
138-
|----------|-------|
139-
| LIVE_ENV | The name of the earlier created environment |
140-
141-
This variable is referenced in {file}`.github/workflows/manual_deploy.yml`.
142138

143139
## Initiating Manual Deployment
144140

docs/plone-deployment/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ Many sections may be zipped through in a class, noting to students that the full
3232
intro
3333
setup
3434
plone-stack
35+
virtual-host
3536
plone-docker-images
3637
project-new
3738
project-start
3839
project-edit
3940
server-setup
4041
deploy
41-
virtual-host
4242
troubleshoot
4343
```

docs/plone-deployment/intro.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ myst:
99

1010
# Introduction
1111

12-
This training material provides insights into deploying Plone for production.
13-
We aim to impart skills for automating deployment processes,
14-
ensuring that you can transform a fresh Linux server into an efficient and robust Plone server.
12+
This training provides practical guidance for deploying Plone in production.
13+
It focuses on automating deployments so you can reliably transform a fresh Linux server into a production-ready Plone instance.
1514

1615
## Target Audience
1716

@@ -20,17 +19,29 @@ or considering a virtual machine on your personal computer for testing, this tra
2019

2120
## Objectives
2221

22+
- Describe the lifecycle of a Plone project.
2323
- Achieve repeatable deployments.
2424
- Ensure consistency across multiple deployment instances.
2525
- Impart knowledge on the tools reflecting the Plone community's preferences.
2626

27-
## Training Content
27+
## Different types of Plone codebases
2828

29-
We will delve into a basic setup, scalable to accommodate extensive Plone installations.
29+
In the Plone ecosystem there are three common codebase types:
30+
31+
| Type | Definition | Example |
32+
| -- | -- | -- |
33+
| Distribution | An opinionated packaging of Plone, usually focused on a vertical market or specific use case. | kitconcept Intranet, Quaive, ioCommune |
34+
| Add-On | A package (or group of packages) that extends Plone with new features. | EEA Accordion, Volto Form Support, Volto Light Theme, Collective Tech Event |
35+
| Project | A specific implementation of Plone (or a Plone-based distribution) used to create a site, intranet, or knowledge base. | Plone Conference Site, Plone.org, DLR.de |
36+
37+
Add-ons are typically tested against a matrix of supported versions: backend add-ons against multiple Python and Plone versions, and frontend add-ons against Node and Volto version matrices. Distributions are released with a narrower, opinionated set of pinned dependencies to reduce integration complexity.
38+
39+
Project codebases generally require strict repeatability and therefore pin exact dependency versions.
40+
For projects managed with `zc.buildout`, it has been best practice to include a `versions.cfg` file that controls package versions. In this training we follow the same principle: we use a backend lockfile ( `uv.lock`) and `pnpm-lock.yaml` for the frontend.
3041

3142
(deployment-training-choices)=
3243

33-
### Training Choices
44+
### Training choices
3445

3546
#### Linux
3647

@@ -39,21 +50,19 @@ However, any system capable of running Python should suffice for development pur
3950

4051
#### Major Distributions
4152

42-
We support and recommend Ubuntu LTS for server setup. Debian and other distributions with up-to-date packages are also compatible.
53+
We recommend Ubuntu LTS for server deployments. Debian and other stable distributions with up-to-date packages are also supported.
4354

4455
#### Platform Packages
4556

46-
Prioritize platform packages to leverage automatic updates. Opt for usability over the latest versions to ensure stability and security.
57+
Prefer using distribution-packaged system packages where practical to benefit from automatic security updates and easier maintenance. Favor stability and maintainability over running the absolute latest upstream versions on production systems.
4758

4859
#### Ansible
4960

50-
Ansible stands out for its serverless nature, Python foundation, and user-friendly YAML configuration language,
51-
making it a preferred choice for deployment automation.
61+
Ansible is a natural fit for our automation needs: it's agentless, written in Python, and uses readable YAML playbooks. Its idempotent design and role-based structure make it a good choice for repeatable server provisioning.
5262

5363
#### Docker and Docker Swarm
5464

55-
Embrace the consistency and repeatability offered by containers. Docker, complemented by Docker Swarm,
56-
simplifies the setup process, making it accessible even for beginners.
65+
Containers provide consistency and repeatability. Docker (and Docker Compose for local orchestration) is used throughout this training; Docker Swarm is the recommended option for lightweight orchestration in production scenarios covered here.
5766

5867
#### GitHub and GitHub Actions
5968

@@ -62,4 +71,4 @@ The principles outlined are adaptable to GitLab, Jenkins, and similar platforms.
6271

6372
#### Kubernetes
6473

65-
While the current training edition doesn't cover Kubernetes, we anticipate its inclusion in future updates.
74+
This edition of the training does not cover Kubernetes, but we expect to include Kubernetes-based deployment patterns in a future update. The Plone community maintains Helm charts that can be used as a starting point: https://github.com/plone/helm-charts

docs/plone-deployment/plone-docker-images.md

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ myst:
99

1010
# Plone Docker Images
1111

12-
Since the release of Plone 6, the community has a new set of Docker images offering more base options.
12+
Since the release of Plone 6, the community has a new set of public Docker images offering most base options, and documenting the configuration. They are meant as a way to quickly start a project, and provide inspiration for your own projects advanced requirements.
1313

1414
## `plone/plone-frontend`
1515

16-
Repository available at https://github.com/plone/plone-frontend/.
16+
Repository is available at https://github.com/plone/plone-frontend/.
1717

1818
Installs the Plone 6 user-experience using the React-powered frontend, Volto.
1919

20-
Should be used to showcase the Plone 6 experience, as new projects will probably implement their own Docker images (with a similar Dockerfile), like the one below:
20+
Should be used to showcase the Plone 6 experience, and how to build images in multiple stages to reduce image size. New projects will probably implement their own Docker images (with a similar Dockerfile), like the one below:
2121

2222
```Dockerfile
2323
# syntax=docker/dockerfile:1
@@ -58,10 +58,11 @@ EOT
5858

5959
Repository available at https://github.com/plone/plone-backend/.
6060

61-
Installs the Plone 6 backend using a pip-based installation.
62-
This approach makes it easier and faster to extend this image in your own project.
61+
Installs the Plone 6 backend using a package-based installation.
6362

64-
One example of such extension would be:
63+
There are currently two distinct approaches to use the backend base images in your project:
64+
65+
### Usage with `pip` + `mxdev`
6566

6667
```Dockerfile
6768
# syntax=docker/dockerfile:1
@@ -93,7 +94,7 @@ EOT
9394
FROM plone/server-prod-config:${PLONE_VERSION}
9495

9596
LABEL maintainer="Plone Community <collective@plone.org>" \
96-
org.label-schema.name="ploneconf2024-training-backend" \
97+
org.label-schema.name="ploneconf2025-training-backend" \
9798
org.label-schema.description="Plone Conference Training Backend." \
9899
org.label-schema.vendor="Plone Community"
99100

@@ -106,8 +107,85 @@ RUN <<EOT
106107
EOT
107108
```
108109

110+
### Usage with `uv` (Experimental)
111+
112+
To use these images, your project should be already using `uv` and have a `pyproject.toml` section with additional dependencies to be installed inside a container:
113+
114+
```toml
115+
[dependency-groups]
116+
...
117+
container = [
118+
"plone.app.upgrade",
119+
"psycopg2==2.9.10",
120+
"relstorage==4.1.1",
121+
"zeo==6.0.0",
122+
]
123+
```
124+
125+
The `Dockerfile` will look like:
126+
127+
```Dockerfile
128+
# syntax=docker/dockerfile:1.9
129+
ARG PYTHON_VERSION=3.12
130+
FROM plone/server-builder:uv-${PYTHON_VERSION} AS builder
131+
132+
# Install dependencies
133+
RUN --mount=type=cache,target=/root/.cache \
134+
--mount=type=bind,source=uv.lock,target=uv.lock \
135+
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
136+
uv sync \
137+
--locked \
138+
--no-dev \
139+
--no-group test \
140+
--group container \
141+
--no-install-project
142+
143+
COPY . /src
144+
WORKDIR /src
145+
146+
# Install package
147+
RUN --mount=type=cache,target=/root/.cache \
148+
uv sync \
149+
--locked \
150+
--no-dev \
151+
--no-group test \
152+
--group container \
153+
--no-editable
154+
155+
# Move skeleton files to /app
156+
RUN <<EOT
157+
mv /app_skeleton/* /app
158+
rm -Rf /app_skeleton
159+
mv container/docker-entrypoint.sh /app/docker-entrypoint.sh
160+
chmod +x /app/docker-entrypoint.sh
161+
mv scripts/create_site.py /app/scripts/create_site.py
162+
EOT
163+
164+
# Compile translation files
165+
RUN <<EOT
166+
/app/bin/python /compile_mo.py
167+
EOT
168+
169+
FROM plone/server-prod-config:uv-${PYTHON_VERSION}
170+
171+
LABEL maintainer="Plone Community <collective@plone.org>" \
172+
org.label-schema.name="ploneconf2025-training-backend" \
173+
org.label-schema.description="Plone Conference Training Backend." \
174+
org.label-schema.vendor="Plone Community"
175+
176+
# Copy the pre-built `/app` directory to the runtime container
177+
# and change the ownership to user app and group app in one step.
178+
COPY --from=builder --chown=500:500 /app /app
179+
180+
RUN <<EOT
181+
ln -s /data /app/var
182+
chown -R 500:500 /data
183+
EOT
184+
```
185+
186+
109187
## `plone/plone-zeo`
110188

111189
Repository available at https://github.com/plone/plone-zeo/.
112190

113-
Installs a ZEO database server.
191+
Provides a ZEO database server for your container based Plone CMS Stack. This allows you to scale to multiple backends without a relational Database like PostgreSQL or MySQL to store the content data.

docs/plone-deployment/plone-stack.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ myst:
1010

1111
Explore the intricate components of the Plone stack, tailored for deploying a modern Plone 6 site with a ReactJS-powered frontend.
1212
For deployments focusing on Plone Classic UI with server-side HTML rendering, the frontend component is excluded.
13-
This guide won't cover the integration of a web accelerator or the setup of an edge caching service.
13+
This guide won't explain all the details regarding the integration of a web accelerator or the setup of an edge caching service.
1414

1515
## Components of the Plone Stack
1616

@@ -26,15 +26,22 @@ To understand the rewrite rules used in Traefik, please read our reference about
2626

2727
### Plone Frontend
2828

29-
Hosted on a Node.js HTTP-server running on port 3000, the Plone frontend constitutes the default user interface and requires access to the Plone Backend and the web server.
29+
Hosted on a Node.js HTTP-server running on port 3000, the Plone frontend constitutes the default user interface. It serves a sever side rendered html version of the webpage and delivers the javascript bundles for the dynamic web application runnin gin the browser. It requires access to the Plone Backend and is exposed through the webserver and Accelerator.
3030

3131
### Plone Backend
3232

33-
Operating on port 8080, the Plone Backend, a WSGI process, serves as the HTTP server hosting the Plone API. It's optimal to pair it with a specialized database like ZEO server or a relational database via RelStorage, supporting PostgreSQL, MySQL/MariaDB, and Oracle. A separate shared file system is essential for storing binary data if ZEO is employed.
33+
Operating on port 8080, the Plone Backend, Python WSGI process, serves as the Application server hosting the Plone REST API. It delivers the content to the frontend Server and Browsers, stores it persistently in a backendd database or on filesystrem, and provides management API and security, like moving/copying content, advanced worfklows, security, etc.
34+
35+
It's optimal to pair it with a specialized database like ZEO server or a relational database
3436

3537
### Database
3638

37-
The database layer can range from a simple ZODB with file storage to more scalable options like a ZEO server or a relational database. This training will focus on using a PostgreSQL instance.
39+
The database layer can range from a simple ZODB with file storage to more scalable options like a ZEO server or a relational database via RelStorage, supporting PostgreSQL, MySQL/MariaDB, and Oracle. In the most simple version, the Plone backend can open a database on the local filesystem. But in this setup you are limited to only one backend. If you use ZEO, multiple Plone backends open a connection to the ZEO server, which manages the ZODB files. A separate shared file system like NFS is essential for storing binary data and sharing it to the backends with a ZEO setup.
40+
41+
This training will focus on using a PostgreSQL instance. With a relational database, the backends connect through the RelStorage Adapter to the Database, where the ZODB is mapped in a very basic way to a number of specialised tables and fields to hold all data.
42+
43+
Storing binary data (blobs) in a relational database or keeping them seperate in a blob storage is an advanced discussion and has different trade offs when looking at
44+
performance and high availability.
3845

3946
## Deployment Configurations
4047

@@ -70,10 +77,10 @@ Web server → Web Accelerator → Plone Frontend → Plone Backend → Database
7077

7178
In a multi-server environment, load distribution and redundancy are achieved through various configurations, enabling horizontal scaling.
7279

73-
```{figure} _static/request_flow.png
74-
:alt: Flow of a request to `https://example.com`
80+
```{figure} _static/request_flow.svg
81+
:alt: Flow of a request to `https://plone.example.com`
7582

76-
Flow of a request to https://example.com
83+
Flow of a request to https://plone.example.com
7784
```
7885

7986
#### Web server and Web Accelerator Layer
@@ -88,3 +95,9 @@ Hosts scalable Plone Frontend and Backend processes, enhancing performance and r
8895

8996
Can host a ZEO server or a relational database. Managed relational database services with backup and replication are
9097
recommended for those unfamiliar with database management, with PostgreSQL being a preferred choice.
98+
99+
### Scaling and High Availability
100+
101+
The components of the CMS Stack as described above, can all run in a parallelized, distributed, and optionally high available setup. There are however extra requirements for some of the building blocks. The ingress web server (Traefik) can run multiple instances, but needs a way to sync TLS certificates and route information. The Varnish server can be run multiple times, but purge requests for changed/stale contenct, will need to be multiplied to all cache instances.
102+
103+
The Plone frontend and backend servers can and should run with multiple instances in a larger setup to offer enough throughput. Lastly, the database should be dimensioned large enough to support al storage/retrieve requests from the Backends. When high availability is required, the database layer should be set up with Relstorage and a Relational Database that is configured accordingly (for example primary/secondary with active failover, or a a three node DB cluster).

0 commit comments

Comments
 (0)