15 - Your First Contribution¶
What this session is¶
The whole thing. We walk through making a real contribution to a real containerized OSS project, end-to-end.
The workflow¶
Identical to the workflow in the other beginner paths:
- Fork on GitHub.
- Clone your fork.
- Add upstream as remote.
- Branch off main.
- Set up: ensure
docker buildworks on a fresh clone. - Change the Dockerfile / compose.yaml / docs.
- Test locally: rebuild, run, verify nothing broke.
- Push to your fork; open PR.
Step 1: Fork & clone¶
GitHub → Fork (top right). Then:
git clone git@github.com:<you>/<project>.git
cd <project>
git remote add upstream git@github.com:<owner>/<project>.git
git fetch upstream
Step 2: Branch¶
Branch names should hint at the change.
Step 3: Verify the baseline¶
Should succeed. If it doesn't on a fresh clone, fix that first (or ask in the issue).
Step 4: Make the change¶
Edit the Dockerfile. Suppose your change is "add a non-root user." Before:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
After:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd --create-home --shell /bin/bash --uid 1001 app && \
chown -R app:app /app
USER 1001:1001
CMD ["python", "app.py"]
Step 5: Test¶
docker build -t test:after .
docker run --rm test:after id # should report uid=1001
docker run --rm test:after python app.py # should still work
If the app needs to write somewhere (e.g. a cache dir), confirm permissions are correct.
If the project has a compose.yaml, test that too:
Step 6: Run CI's checks locally¶
Open the CI workflow (.github/workflows/*.yml). Whatever it runs, run those commands too:
docker buildx build --platform linux/amd64,linux/arm64 .- multi-arch test.hadolint Dockerfile- Dockerfile linter (install:brew install hadolintor use the Docker image).trivy image test:after- vulnerability scan.
If any fail, fix before pushing.
Step 7: Commit & push¶
git add Dockerfile
git commit -m "Dockerfile: run as non-root user (UID 1001)"
git push origin fix/dockerfile-non-root-user
Commit message conventions vary by project. Some require Conventional Commits (fix:, feat:); most don't.
Step 8: Open the PR¶
On the upstream repo, click "Compare & pull request."
- Title. Mirror the commit message.
- Description. What changed, why, how you tested. If there's a related issue:
Closes #123. - Checklist. Address every item in the PR template.
Submit. CI runs. Fix anything red by pushing more commits to the same branch.
What review looks like¶
A maintainer reads. Outcomes:
1. "LGTM, merging." Done.
2. "Could you change these?" Most common. Address each comment, push commits.
3. "Not what we want." Rare for good first issue work. Ask about related work.
4. Silence. Polite check-in after 1 week; escalate after 3.
Address feedback efficiently. Disagree only on substance.
After the merge¶
- Update your fork's
main. - Delete the branch.
- Take a screenshot.
- Sit with it for a day.
Worked example: contributing to docker-library/python (hypothetical)¶
Suppose you noticed docker-library/python doesn't have an example in its README for using build arguments to pin a Python patch version. You decide to add one.
git clone git@github.com:<you>/docker-python.git
cd docker-python
git remote add upstream git@github.com:docker-library/python.git
git fetch upstream
git checkout -b docs/add-build-arg-example
# Edit README.md, add the example.
# Test that the README renders correctly (markdown preview in your editor).
git add README.md
git commit -m "Add example: pinning Python patch version via build-arg"
git push origin docs/add-build-arg-example
Open PR. Wait for review. Address style nits ("please use fenced code blocks with dockerfile language tag"). Push fixes. Merge.
You're now a docker-library contributor.
After your first PR: what next¶
- Pick another issue in the same project. Familiarity compounds.
- After 3-5 PRs, become a regular. Watch issues, help others, review PRs (you don't need maintainer permissions to leave helpful comments).
- Branch out to Tier 3-4 projects.
- Build your own containerized service. Publish the image. Maintain the Dockerfile.
- Pick the next path: Kubernetes From Scratch is the natural follow-up.
What you might wonder¶
"PR sits for weeks?" Polite check-in after 1 week. After 3, ask in the project's chat/discussions.
"My change broke CI?" Read the failing job's logs. Fix locally, push another commit. The PR updates automatically.
"Maintainer rude?" Disengage. Try another project.
"Can I list this on a CV?" Yes - link to specific merged PRs.
Done with this path¶
You've: - Installed Docker, run your first containers. - Built your own images with Dockerfile. - Used volumes, networks, ports. - Composed multi-container apps. - Published images to a registry. - Read a real containerized OSS project. - Submitted a PR.
What you should do next: keep using containers daily. Use them for development, for ad-hoc tools, for experiments. Familiarity compounds.
Recommended next paths on this site:
- Kubernetes From Scratch - containers' big sibling. Orchestration, scaling, declarative deploys.
- Container Internals - senior reference path. How containers actually work (namespaces, cgroups, OCI, runtimes). Assumes you've done this path.
- Linux Kernel - the substrate. Containers ARE Linux features.
Congratulations. You are no longer a beginner.