Skip to content

Commit 2a71839

Browse files
authored
Merge pull request #247 from GridOPTICS/docker
Add Docker to GridPACK develop branch
2 parents 96307f6 + 1d03c85 commit 2a71839

18 files changed

Lines changed: 544 additions & 19 deletions

.dockerignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea
2+
external_dependencies
3+
/python/build
4+
/python/dist
5+
/python/gridpack_hadrec.egg-info

.gitmodules

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
[submodule "python/pybind11"]
66
path = python/pybind11
77
url = https://github.com/pybind/pybind11.git
8+
branch = master

Dockerfile

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
FROM ubuntu:questing
2+
3+
# Configure dependency versions
4+
ARG boost_version=1.81.0
5+
ARG ga_version=5.9.1
6+
ARG petsc_version=3.24.2
7+
8+
# Setup environment variables used throughout installation
9+
ENV DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC GNUMAKEFLAGS=--no-print-directory
10+
ENV OMPI_ALLOW_RUN_AS_ROOT=1 OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1
11+
12+
ENV GRIDPACK_ROOT_DIR=/app GP_EXT_DEPS=/deps
13+
ENV GRIDPACK_INSTALL_DIR=${GRIDPACK_ROOT_DIR}/src/install GRIDPACK_BUILD_DIR=${GRIDPACK_ROOT_DIR}/src/build
14+
ENV GRIDPACK_DIR=${GRIDPACK_INSTALL_DIR}
15+
16+
ENV boost_dir=${GP_EXT_DEPS}/boost-${boost_version} \
17+
ga_dir=${GP_EXT_DEPS}/ga-${ga_version} \
18+
petsc_dir=${GP_EXT_DEPS}/petsc
19+
20+
ENV boost_gp_dir=${boost_dir}/install_for_gridpack \
21+
ga_gp_dir=${ga_dir}/install_for_gridpack \
22+
petsc_gp_dir=${petsc_dir}/install_for_gridpack
23+
24+
ENV PETSC_DIR=${petsc_dir} PETSC_ARCH=build-dir
25+
26+
ENV LD_LIBRARY_PATH=${boost_gp_dir}/lib:${ga_gp_dir}/lib:${petsc_gp_dir}/lib
27+
ENV DYLD_LIBRARY_PATH=${LD_LIBRARY_PATH}
28+
29+
# Install required system packages
30+
RUN apt-get update && \
31+
apt-get install -y --no-install-recommends cmake make wget tzdata git gfortran build-essential pkg-config \
32+
python3 python3-pip python3-venv python3-dev python-is-python3 \
33+
openmpi-bin openmpi-common openmpi-doc libopenmpi-dev && \
34+
apt-get clean
35+
36+
# Compile/Install Boost
37+
WORKDIR ${GP_EXT_DEPS}
38+
RUN wget "https://github.com/boostorg/boost/releases/download/boost-${boost_version}/boost-${boost_version}.tar.gz"
39+
RUN tar -xf "boost-${boost_version}.tar.gz"
40+
WORKDIR ${boost_dir}
41+
RUN ./bootstrap.sh --prefix=install_for_gridpack --with-libraries=mpi,serialization,random,filesystem,system
42+
RUN echo 'using mpi : mpicxx ; ' >> project-config.jam
43+
RUN ./b2 -a -d+2 link="shared" stage
44+
RUN ./b2 -a -d+2 link="shared" install
45+
46+
# Compile/Install GA (Global Arrays)
47+
WORKDIR ${GP_EXT_DEPS}
48+
RUN wget "https://github.com/GlobalArrays/ga/releases/download/v${ga_version}/ga-${ga_version}.tar.gz"
49+
RUN tar -xf "ga-${ga_version}.tar.gz"
50+
WORKDIR ${ga_dir}
51+
RUN ./configure --with-mpi-ts --disable-f77 \
52+
--without-blas --without-lapack --without-scalapack \
53+
--enable-cxx --enable-i4 \
54+
--prefix=${ga_gp_dir} \
55+
CFLAGS="-Wno-implicit-function-declaration -Wno-incompatible-pointer-types -Wno-old-style-definition" \
56+
CXXFLAGS="-Wno-incompatible-pointer-types" \
57+
--enable-shared=yes --enable-static=no
58+
RUN make -j 10 install
59+
WORKDIR ${GP_EXT_DEPS}
60+
61+
# Compile/Install PETSc
62+
RUN git clone https://gitlab.com/petsc/petsc.git
63+
WORKDIR ${petsc_dir}
64+
RUN git checkout "tags/v${petsc_version}" -b "v${petsc_version}"
65+
RUN ./configure \
66+
--prefix=${PWD}/install_for_gridpack \
67+
--scalar-type=real \
68+
--with-fortran-bindings=0 \
69+
--download-superlu_dist \
70+
--download-metis \
71+
--download-parmetis \
72+
--download-suitesparse \
73+
--download-f2cblaslapack \
74+
--download-scalapack \
75+
--download-mumps \
76+
--download-cmake=0 \
77+
--with-sowing=0 \
78+
--with-debugging=0 \
79+
--with-shared-libraries=1
80+
RUN make all
81+
RUN make install
82+
#RUN make PETSC_DIR=${petsc_gp_dir} PETSC_ARCH="" check
83+
84+
# Copy in GridPACK source code from repository
85+
COPY README.md .gitignore .gitmodules ${GRIDPACK_ROOT_DIR}/
86+
COPY .git ${GRIDPACK_ROOT_DIR}/.git
87+
COPY docs ${GRIDPACK_ROOT_DIR}/docs
88+
COPY python ${GRIDPACK_ROOT_DIR}/python
89+
COPY src ${GRIDPACK_ROOT_DIR}/src
90+
91+
# Build GridPACK
92+
WORKDIR ${GRIDPACK_BUILD_DIR}
93+
RUN cmake -Wdev -D GA_DIR:STRING=${ga_gp_dir} \
94+
-D Boost_ROOT:STRING=${boost_gp_dir} \
95+
-D Boost_DIR:string=${boost_gp_dir}/lib/cmake/Boost-${boost_version} \
96+
-D PETSC_DIR:PATH=${petsc_gp_dir} \
97+
-D MPI_CXX_COMPILER:STRING='mpicxx' \
98+
-D MPI_C_COMPILER:STRING='mpicc' \
99+
-D MPIEXEC:STRING='mpiexec' \
100+
-D MPIEXEC_MAX_NUMPROCS:STRING=2 \
101+
-D GRIDPACK_TEST_TIMEOUT:STRING=120 \
102+
-D ENABLE_ENVIRONMENT_FROM_COMM:BOOL=YES \
103+
-D CMAKE_INSTALL_PREFIX:PATH=${GRIDPACK_INSTALL_DIR} \
104+
-D CMAKE_BUILD_TYPE:STRING=Debug \
105+
-D BUILD_SHARED_LIBS=true \
106+
-D CMAKE_CXX_FLAGS_DEBUG:STRING="-D_GLIBCXX_NO_ASSERTIONS" \
107+
..
108+
RUN make install
109+
110+
# Install Python bindings
111+
WORKDIR ${GRIDPACK_ROOT_DIR}
112+
RUN git submodule update --init
113+
RUN pip config --global set global.break-system-packages true
114+
WORKDIR ${GRIDPACK_ROOT_DIR}/python
115+
RUN pip install --upgrade --prefix=${GRIDPACK_INSTALL_DIR} .
116+
117+
# Configure Python module search path using .pth file (no environment variables needed)
118+
# Python automatically reads .pth files from its site-packages directories
119+
RUN pyvnum=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') && \
120+
system_site_packages=$(python3 -c 'import site; print(site.getsitepackages()[0])') && \
121+
echo "${GRIDPACK_INSTALL_DIR}/lib/python${pyvnum}/site-packages" > ${system_site_packages}/gridpack.pth && \
122+
echo "${GRIDPACK_INSTALL_DIR}/local/lib/python${pyvnum}/dist-packages" >> ${system_site_packages}/gridpack.pth && \
123+
echo "Configured Python ${pyvnum} module search path via ${system_site_packages}/gridpack.pth"
124+
125+
WORKDIR ${GRIDPACK_ROOT_DIR}/workspace
126+
ENV PATH=${GRIDPACK_INSTALL_DIR}/bin:${GRIDPACK_INSTALL_DIR}/local/bin:${PATH}

Dockerfile.test

Lines changed: 0 additions & 10 deletions
This file was deleted.

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,32 @@ In addition, GridPACK is also a framework to simplify the development of new app
1717
## Installation
1818
See the [instructions](docs/markdown/BASIC_INSTALL.md) for installing GridPACK, prerequisite software, and installation notes for different platforms. Formal releases are available [here](https://github.com/GridOPTICS/GridPACK/releases).
1919

20+
### Using Docker (Recommended)
21+
22+
GridPACK is available as a multi-architecture Docker image with all dependencies pre-installed:
23+
24+
```bash
25+
# Pull the image
26+
docker pull pnnl/gridpack:latest
27+
28+
# Run with your files (container starts in /app/workspace)
29+
docker run -it --rm -v $(pwd):/app/workspace pnnl/gridpack:latest bash
30+
```
31+
32+
The Docker image supports both AMD64 and ARM64 architectures. See the [Docker usage guide](https://gridpack.readthedocs.io/en/latest/Section2-Docker.html) for more examples.
33+
34+
### Building from Source
35+
36+
See the [installation instructions](docs/markdown/BASIC_INSTALL.md) for building GridPACK from source, prerequisite software, and platform-specific installation notes. Formal releases are available [here](https://github.com/GridOPTICS/GridPACK/releases).
37+
2038
## Usage
2139
See the [user manual](https://gridpack.readthedocs.io/en/latest/index.html) for a deep dive on GridPACK internals and/or refer to the [tutorials](docs/markdown/TUTORIALS.md) for more info.
2240

2341
- Quick Guide (To do)
2442

2543
## Documentation
44+
- [Docker Usage Guide](https://gridpack.readthedocs.io/en/latest/Section2-Docker.html)
45+
- [CI/CD Pipeline](docs/markdown/CI-CD.md)
2646
- [User manual](https://gridpack.readthedocs.io/en/latest/index.html)
2747
- [Tutorials](docs/markdown/TUTORIALS.md)
2848
- [FAQS](docs/markdown/FAQS.md)

docs/markdown/CI-CD.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# CI/CD Pipeline Documentation
2+
3+
## Overview
4+
5+
GridPACK uses GitHub Actions to build multi-architecture Docker images that are automatically published to Docker Hub at `pnnl/gridpack`.
6+
7+
## Pipeline Architecture
8+
9+
The pipeline uses native ARM64 and AMD64 runners for optimal build performance:
10+
11+
```
12+
prepare-metadata → build-native (amd64 + arm64) → merge-manifest → test-native (amd64 + arm64)
13+
↓ parallel ↓ ↓ ↓ parallel ↓
14+
```
15+
16+
### Jobs
17+
18+
1. **prepare-metadata**: Generates Docker tags and labels
19+
2. **build-native**: Builds images natively on AMD64 and ARM64 runners in parallel
20+
3. **merge-manifest**: Stitches architecture-specific images into a multi-arch manifest
21+
4. **test-native**: Runs ctest smoke tests on both architectures in parallel
22+
23+
### Performance
24+
25+
- **Native ARM64 builds**: 3-10x faster than QEMU emulation
26+
- **Parallel execution**: Both architectures build simultaneously
27+
- **Total build time**: ~20-35 minutes (vs 45-90 minutes with QEMU)
28+
29+
## Triggers
30+
31+
### Automatic: Release Published
32+
33+
When a GitHub release is created, the pipeline automatically builds and publishes:
34+
35+
```bash
36+
gh release create v3.3.0 --title "Release 3.3.0" --notes "Release notes"
37+
```
38+
39+
Generated tags:
40+
- `pnnl/gridpack:3.3.0`
41+
- `pnnl/gridpack:3.3`
42+
- `pnnl/gridpack:latest`
43+
44+
### Manual: Workflow Dispatch
45+
46+
Trigger builds manually from the GitHub Actions UI or CLI:
47+
48+
**Via GitHub UI:**
49+
1. Go to: Actions → Docker Multi-Architecture Build and Publish
50+
2. Click "Run workflow"
51+
3. Configure options:
52+
- **tag**: Custom Docker tag (default: `dev`)
53+
- **skip_tests**: Skip ctest smoke tests (default: `false`)
54+
- **dockerfile**: Dockerfile path (default: `./Dockerfile`)
55+
4. Click "Run workflow"
56+
57+
**Via GitHub CLI:**
58+
59+
```bash
60+
# Basic run with defaults
61+
gh workflow run docker-build.yml
62+
63+
# With custom tag
64+
gh workflow run docker-build.yml -f tag=test-build
65+
66+
# Skip tests for faster iteration
67+
gh workflow run docker-build.yml -f skip_tests=true
68+
69+
# Use custom Dockerfile
70+
gh workflow run docker-build.yml -f dockerfile=./Dockerfile.custom
71+
```
72+
73+
## Docker Image
74+
75+
### Repository
76+
- **Location**: `pnnl/gridpack`
77+
- **Registry**: Docker Hub
78+
79+
### Supported Architectures
80+
- `linux/amd64` (Intel/AMD)
81+
- `linux/arm64` (ARM64/Apple Silicon/AWS Graviton)
82+
83+
### Usage
84+
85+
See [Docker Usage Guide](./DOCKER.md) for detailed examples.
86+
87+
## Testing
88+
89+
The pipeline runs ctest smoke tests on both architectures after building. Key points:
90+
91+
- **Non-blocking**: Test failures do NOT prevent image publication (`continue-on-error: true`)
92+
- **Expected pass rate**: ~94%
93+
- **Can be skipped**: Use `skip_tests=true` for faster iteration
94+
95+
## Secrets Required
96+
97+
The pipeline requires two GitHub repository secrets:
98+
99+
| Secret | Description |
100+
|--------|-------------|
101+
| `DOCKERHUB_USERNAME` | Docker Hub username for authentication |
102+
| `DOCKERHUB_TOKEN` | Docker Hub access token (not password!) |
103+
104+
### Setting Up Secrets
105+
106+
1. **Generate Docker Hub Access Token:**
107+
- Go to: https://hub.docker.com → Account Settings → Security
108+
- Create token: Name: `gridpack-ci`, Permissions: Read, Write, Delete
109+
- Copy the token (shown only once)
110+
111+
2. **Add to GitHub:**
112+
- Go to: Repository Settings → Secrets and variables → Actions
113+
- Add both secrets with the values above
114+
115+
## Monitoring
116+
117+
### View Workflow Runs
118+
119+
```bash
120+
# List recent runs
121+
gh run list --workflow=docker-build.yml --limit 5
122+
123+
# Watch a specific run
124+
gh run watch <run-id>
125+
126+
# View detailed logs
127+
gh run view <run-id> --log
128+
```
129+
130+
### Inspect Published Image
131+
132+
```bash
133+
# View manifest with both architectures
134+
docker buildx imagetools inspect pnnl/gridpack:latest
135+
136+
# Expected output shows:
137+
# - linux/amd64 manifest
138+
# - linux/arm64 manifest
139+
```
140+
141+
## Caching
142+
143+
The pipeline uses GitHub Actions cache to speed up builds:
144+
145+
- Separate cache per architecture (`build-amd64`, `build-arm64`)
146+
- Automatically managed by GitHub
147+
- Improves rebuild times significantly
148+
149+
## Troubleshooting
150+
151+
### Build Fails on One Architecture
152+
153+
The pipeline uses `fail-fast: false`, so if one architecture fails, the other continues. Check job logs for architecture-specific issues.
154+
155+
### Manifest Merge Fails
156+
157+
This usually indicates both architecture builds failed. Check that:
158+
- Docker Hub credentials are correct
159+
- Both build jobs completed successfully
160+
- Digest artifacts were uploaded
161+
162+
### Authentication Issues
163+
164+
Verify secrets are configured correctly:
165+
```bash
166+
gh secret list
167+
```
168+
169+
Should show:
170+
- `DOCKERHUB_USERNAME`
171+
- `DOCKERHUB_TOKEN`
172+
173+
## Technical Details
174+
175+
### Push-by-Digest Workflow
176+
177+
The pipeline uses a digest-based approach:
178+
179+
1. Each architecture builds and pushes: `pnnl/gridpack@sha256:abc123...`
180+
2. These are content-addressed (by digest), not tagged yet
181+
3. Manifest merge creates tags that reference both digests
182+
4. Docker automatically selects the right image based on client platform
183+
184+
### Why Native Runners?
185+
186+
- **Performance**: 3-10x faster ARM64 builds without QEMU
187+
- **Reliability**: No emulation issues or crashes
188+
- **Testing**: Tests run on actual target platforms
189+
- **Cost**: Same GitHub Actions pricing as AMD64
190+
191+
## Workflow File
192+
193+
Location: `.github/workflows/docker-build.yml`
194+
195+
The workflow definition must be in the default branch to be accessible. Changes to the workflow require merging to the default branch.
196+
197+
## Future Enhancements
198+
199+
Potential improvements:
200+
- Additional architectures (RISC-V when runners available)
201+
- Multi-registry support (GitHub Container Registry)
202+
- Build time metrics/reporting
203+
- Automated security scanning per architecture
File renamed without changes.

0 commit comments

Comments
 (0)