Example Dockerfiles
This document provides Dockerfile examples created to work with PartyBus pipelines. In addition, the following video provides a tutorial on the example Dockerfiles.
Why?
The build-image stage in the pipeline has egress locked down. This is done to prevent teams from bringing in dependencies that haven't been checked by the SCA stage.
Because of this, the Dockerfile examples below are configured specifically to work with artifacts generated from the CI/CD pipeline.
This is comparable to the process of getting through TSA at the airport. Once a person passes through TSA, items from outside can't be brought in.
How do I download my dependencies and copy them into the image?
This is the purpose of the build stage. The build stage will download your dependencies and save them off in gitlab's cache or job artifacts depending on the template. Files that are saved off are pulled down in subsequent jobs.
Cache | Artifacts |
---|---|
Carries over into subsequent pipeline runs of the same branch. | Carries over to subsequent jobs in the same pipeline. |
You'll notice that the Dockerfile examples below have a COPY command that handles bringing over dependencies saved off in the build stage.
Rules to Remember
- A Dockerfile must be at the root of each project that requires a pipeline.
- Dockerfiles must be compliant with the examples provided. No packages can be installed in the Dockerfile (this is taken care of during the build stage).
- If you would like to change the Dockerfile used in the pipeline you can set the CI/CD variable
DOCKERFILE_LOC
in your project's settings. (e.g.DOCKERFILE_LOC=Dockerfile.partybus
) - If you need a package installed, please make a request with the MDO team during the pipeline creation process or through a ticket .
- Monolithic repos are not allowed.
- End user cannot be root.
React World App
React World
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs16:16.16.0 AS builder
USER node
WORKDIR /home/node
COPY --chown=node:node . .
EXPOSE 8080
RUN npm run build
# Stage 2
FROM registry1.dso.mil/ironbank/opensource/nginx/nginx:1.21.1
USER nginx
COPY --from=builder --chown=nginx:nginx /home/node/build /etc/nginx/html
COPY --from=builder --chown=nginx:nginx /home/node/src /app/src
EXPOSE 8080
CMD [ "nginx", "-g", "daemon off;" ]
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs16:16.16.0 AS builder
WORKDIR /home/node
COPY ./package.json package-lock.json swagger.json ./
COPY src src
RUN npm run build
EXPOSE 8080
USER node
CMD ["node", "src/index.js"]
Ruby
FROM registry1.dso.mil/ironbank/opensource/ruby/ruby27:2.7.6 WORKDIR /app
COPY --chown=default:root . .
ENV PATH /app/bin:$PATH
ENV RAILS_ENV production
ENTRYPOINT ["/app/entrypoint.sh"]
GO
FROM registry1.dso.mil/ironbank/google/golang:1.18
USER golanguser
WORKDIR /app
COPY ./bin .
CMD [ "./main" ]
CPP
FROM registry1.dso.mil/ironbank/redhat/ubi/ubi8-minimal:8.4
USER root
WORKDIR /app
ARG CMAKE_BUILD_DIR="build"
COPY ${CMAKE_BUILD_DIR}/cpp-world ./
USER nobody
ENTRYPOINT ["/app/cpp-world"]
Maven
FROM registry1.dso.mil/ironbank/redhat/openjdk/openjdk17:1.17
USER appuser
COPY target/*.jar /app/
ENTRYPOINT ["java","-jar","/app/maven-boot-world-0.0.1-SNAPSHOT.jar"]
Yarn
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs16:16.16.0
USER appuser
WORKDIR /home/appuser
ENV NPM_CONFIG_CACHE=/home/appuser/.npm
COPY --chown=appuser:appuser . .
EXPOSE 8080
CMD [ "npm", "start" ]
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs16:16.16.0
USER node
WORKDIR /home/node
COPY --chown=node:node . .
RUN npm prune --production
# cypress libs may have vuln
RUN npm uninstall cypress
EXPOSE 8080
CMD [ "node", "src/index.js" ]
Python
FROM registry1.dso.mil/ironbank/opensource/python/python39:v3.11.1
WORKDIR /home/python
COPY --chown=python:python main.py ./
COPY --chown=python:python python-world ./python-world
COPY --chown=python:python .cache/python-packages ./python-packages
ENV PYTHONPATH=/home/python/python-packages
CMD ["python", "/home/python/main.py"]
NPM Package
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs16:16.16.0
USER appuser
WORKDIR /home/appuser
ENV NPM_CONFIG_CACHE=/home/appuser/.npm
COPY --chown=appuser:appuser . .
EXPOSE 8080
CMD [ "npm", "start" ]
Gradle
FROM registry1.dso.mil/ironbank/redhat/openjdk/openjdk17:1.17
USER 1001
COPY build/libs/hello-java-g-0.0.1-SNAPSHOT.jar /app/
ENTRYPOINT ["java", "-jar", "/app/hello-java-g-0.0.1-SNAPSHOT.jar"]
Angular
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs16:16.16.0 AS builder
USER node
WORKDIR /home/node
COPY --chown=node:node . .
# ng build --configuration production
RUN npm run prod
# Stage 2
FROM registry1.dso.mil/ironbank/opensource/nginx/nginx:1.23.1 WORKDIR /app
COPY --chown=nginx:nginx nginx.conf /etc/nginx/nginx.conf
COPY --from=builder --chown=nginx:nginx /home/node/dist/angular-world /var/www
USER appuser
EXPOSE 8080
CMD [ "nginx", "-g", "daemon off;" ]
NGINIX
# STAGE 1: dev build
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs18:18.14.0 AS builder
WORKDIR /home/node
# copy over all code
COPY --chown=node:node . .
# build the app
RUN npm run build
# STAGE 2: final image build
FROM registry1.dso.mil/ironbank/opensource/nginx/nginx:1.23.2
COPY nginx/nginx.conf /etc/nginx/nginx.conf
USER nginx
COPY --from=builder --chown=nginx:nginx /home/node/build /etc/nginx/html
COPY --from=builder --chown=nginx:nginx /home/node/src /app/src
EXPOSE 8080
CMD [ "nginx", "-g", "daemon off;" ]
worker_processes 1;
worker_rlimit_nofile 8192;
error_log /var/log/nginx/error.log;
pid /var/cache/nginx/nginx.pid;
events {
worker_connections 4096;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# TODO(literally anyone but me): Implement log formatting the way efk wants it
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
keepalive_timeout 65;
gzip on;
gzip_min_length 256;
gzip_types
# text/html is always compressed by HttpGzipModule
text/css
text/javascript
text/xml
text/plain
text/x-component
application/javascript
application/json
application/xml
application/rss+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;
server {
listen 8080;
root /var/www;
location / {
try_files $uri $uri/ /index.html =404;
# X-Frame-Options is to prevent from clickJacking attack
add_header X-Frame-Options SAMEORIGIN;
# disable content-type sniffing on some browsers.
add_header X-Content-Type-Options nosniff;
# This header enables the Cross-site scripting (XSS) filter
add_header X-XSS-Protection "1; mode=block";
# This will enforce HTTP browsing into HTTPS and avoid ssl stripping attack
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
# csp header
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'";
}
}
}
Dotnet
FROM registry1.dso.mil/ironbank/redhat/dotnet-core/dotnetcore-aspnet-6.0:6.0
WORKDIR /home/dotnet
COPY dist .
# set DOTNET default host bind and port
ENV ASPNETCORE_URLS=http://+:8080
ENTRYPOINT ["dotnet", "/home/dotnet/dotnet-world.dll"]
Example Dockerfiles
Non-Root User during Execution
### STAGE 1: Build ###
FROM registry1.dso.mil/ironbank/opensource/nodejs/nodejs16:16.16.0 AS builder
USER root
WORKDIR /app
ARG ENVIRONMENT=local
ENV PATH=/app/node_modules/.bin:${PATH} \
ROLE_MAP=role-nobody.json
COPY package*.json /app
COPY $ROLE_MAP /app/filename-file2.json
COPY . /app
RUN node file2env.js filename-file2.json roleMap && \
npm run prerender:$ENVIRONMENT
USER appuser
### STAGE 2: Production Environment ###
FROM registry1.dso.mil/ironbank/opensource/nginx/nginx:1.23.1
COPY --from=builder --chown=nginx:nginx /app/dist/dashboard/browser /usr/share/nginx/html/
ARG PORT=8080
ENV PORT_ENV=$PORT
EXPOSE $PORT
CMD ["bash", "/tmp/entrypoint.sh"]