Bitbucket Server Installation
The installation for Bitbucket itself brings another major challenge, specifically around how configuration files are handled. The good news though, the dockerfiles are relatively unchanged from their source and available at https://hub.docker.com/r/atlassian/bitbucket-server/dockerfile and the available instructions at https://confluence.atlassian.com/bitbucketserver/automated-setup-for-bitbucket-server-776640098.html.
setup.displayName=Bitbucket
setup.baseUrl=https://bitbucket.acme.com
setup.license=BITBUCKET_LICENSE
setup.sysadmin.username=admin
setup.sysadmin.password=admin123
setup.sysadmin.displayName=Admin User
setup.sysadmin.emailAddress=admin@acme.com
#jdbc.driver=org.postgresql.Driver
#jdbc.url=jdbc:postgresql://d1i-doc-dbpg01:5432/bitbucket
jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=jdbc:sqlserver://d1i-doc-dbss01:1433;databaseName=bitbucket;
jdbc.user=bitbucketuser
jdbc.password=ZeCodeIzGood
# run behind nginx ssl
#server.port=7990
#server.secure=true
#server.scheme=https
#server.proxy-port=443
#server.proxy-name=bitbucket.acme.com
version: '3.3'
services:
bitbucket:
image: infra/atlassian/bitbucket:1.0.0
build:
context: .
network: host
args:
ARG_ART_URL: http://d1i-doc-ngbuild:3001
extra_hosts:
- "d1i-doc-ngbuild:172.22.90.2"
FROM infra/java/openjdk-8:1.0.0
# https://bitbucket.org/atlassian-docker/docker-atlassian-bitbucket-server/src/master/
ENV RUN_USER daemon
ENV RUN_GROUP daemon
# https://confluence.atlassian.com/display/BitbucketServer/Bitbucket+Server+home+directory
ENV BITBUCKET_HOME /var/atlassian/application-data/bitbucket
ENV BITBUCKET_INSTALL_DIR /opt/atlassian/bitbucket
WORKDIR $BITBUCKET_HOME
CMD ["/entrypoint.sh", "-fg"]
ENTRYPOINT ["/tini", "--"]
ARG ARG_ART_URL
RUN sed -e "s|APT_URL|${ARG_ART_URL}|" /etc/apt/sources.list.base > /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends fontconfig git perl dos2unix \
&& apt-get clean \
&& rm /etc/apt/sources.list
ARG ARG_ART_URL
RUN curl $ARG_ART_URL/repository/dml/docker/tools/tini -o /tini \
&& chmod +x /tini
COPY entrypoint.sh /entrypoint.sh
RUN dos2unix /entrypoint.sh \
&& chmod +x /entrypoint.sh
ARG DOWNLOAD_URL=$ARG_ART_URL/repository/dml/docker/bitbucket/atlassian-bitbucket-7.21.3.tar.gz
COPY bitbucket.properties $BITBUCKET_HOME/shared/bitbucket.properties
RUN mkdir -p ${BITBUCKET_INSTALL_DIR} \
&& curl -L ${DOWNLOAD_URL} | tar -xz --strip-components=1 -C "${BITBUCKET_INSTALL_DIR}" \
&& chown -R ${RUN_USER}:${RUN_GROUP} ${BITBUCKET_INSTALL_DIR}/ \
&& sed -i -e 's/^# umask/umask/' ${BITBUCKET_INSTALL_DIR}/bin/_start-webapp.sh
#!/bin/bash
set -euo pipefail
# Set recommended umask of "u=,g=w,o=rwx" (0027)
umask 0027
# Setup Catalina Opts
: ${CATALINA_CONNECTOR_PROXYNAME:=}
: ${CATALINA_CONNECTOR_PROXYPORT:=}
: ${CATALINA_CONNECTOR_SCHEME:=http}
: ${CATALINA_CONNECTOR_SECURE:=false}
: ${CATALINA_OPTS:=}
: ${JAVA_OPTS:=}
: ${ELASTICSEARCH_ENABLED:=true}
: ${APPLICATION_MODE:=}
CATALINA_OPTS="${CATALINA_OPTS} -DcatalinaConnectorProxyName=${CATALINA_CONNECTOR_PROXYNAME}"
CATALINA_OPTS="${CATALINA_OPTS} -DcatalinaConnectorProxyPort=${CATALINA_CONNECTOR_PROXYPORT}"
CATALINA_OPTS="${CATALINA_OPTS} -DcatalinaConnectorScheme=${CATALINA_CONNECTOR_SCHEME}"
CATALINA_OPTS="${CATALINA_OPTS} -DcatalinaConnectorSecure=${CATALINA_CONNECTOR_SECURE}"
JAVA_OPTS="${JAVA_OPTS} ${CATALINA_OPTS}"
ARGS="$@"
# Start Bitbucket without Elasticsearch
if [ "${ELASTICSEARCH_ENABLED}" == "false" ] || [ "${APPLICATION_MODE}" == "mirror" ]; then
ARGS="--no-search ${ARGS}"
fi
# Start Bitbucket as the correct user.
if [ "${UID}" -eq 0 ]; then
echo "User is currently root. Will change directory ownership to ${RUN_USER}:${RUN_GROUP}, then downgrade permission to ${RUN_USER}"
PERMISSIONS_SIGNATURE=$(stat -c "%u:%U:%a" "${BITBUCKET_HOME}")
EXPECTED_PERMISSIONS=$(id -u ${RUN_USER}):${RUN_USER}:700
if [ "${PERMISSIONS_SIGNATURE}" != "${EXPECTED_PERMISSIONS}" ]; then
echo "Updating permissions for BITBUCKET_HOME"
mkdir -p "${BITBUCKET_HOME}/lib" &&
chmod -R 700 "${BITBUCKET_HOME}" &&
chown -R "${RUN_USER}:${RUN_GROUP}" "${BITBUCKET_HOME}"
fi
# Now drop privileges
exec su -s /bin/bash "${RUN_USER}" -c "${BITBUCKET_INSTALL_DIR}/bin/start-bitbucket.sh ${ARGS}"
else
exec "${BITBUCKET_INSTALL_DIR}/bin/start-bitbucket.sh" ${ARGS}
fi
The key to this image is the bitbucket.properties file where all the automation magic occurs. Under normal circumstances, configuration files that contain information about your organization should not be baked into the image and rather be injected. However, Bitbucket Server will use this properties file during its initial startup AND modify the file during installation (thus needing write access and permissions). Modifying a properties file here is the major challenge here when looking at docker container architecture. Since we need to make changes to the same properties file after the initial installation to run it behind a proxy, we will have to follow additional steps:
- Startup a fresh Bitbucket with new data volume and connected to a pre-setup empty Database
- Wait for Bitbucket initialization which will populate database and modify the properties file on the bitbucket volume
- Stop Bitbucket and start another sidecar to modify the properties file (inside the bitbucket volume)
- Restart bitbucket
Building and Running
Before the build, add your license key to the properties file to be included in the Docker build.
sed -e "s|BITBUCKET_LICENSE|YOUR-LICENSE-HERE|" images/bitbucket/bitbucket.properties.base > images/bitbucket/bitbucket.properties
Build it with your properties file.
docker-compose -f images/bitbucket/docker-compose.yml build
#docker login docker-private.acme.com
images/docker-push.sh infra/atlassian/bitbucket:1.0.0 docker-private.acme.com
Important Note: This image will now contain private information, in this case your Bitbucket license.
As we have already completed our database volume, we simply start Bitbucket via the below compose for the initial install to prep our bitbucket docker volume.
version: '3.3'
services:
bitbucket:
image: infra/atlassian/bitbucket:1.0.0
volumes:
- bitbucket-data:/var/atlassian/application-data/bitbucket
ports:
- 7990:7990
- 7999:7999
networks:
- ops-network
networks:
ops-network:
name: ops-network
volumes:
bitbucket-data:
name: bitbucket-data
Run the initialization.
docker-compose -f composed/docker-compose-bitbucket-init.yml up
The install will take aprox 2 minutes total and once completed will show you the login page at http://localhost:7990 with the ability to login as admin:admin123. Once completed stop the container.
Running it behind NGINX
As stated during our Nexus3 Infrastructure Install, we want to re-use our NGINX that currently proxies Nexus to now also include bitbucket so we can access it via https://bitbucket.acme.com.
This base NGINX will create a wildcard self signed SSL under *.acme.com allowing us to run many of our DevOps apps behind the same nginx as we continue.
While it may appear adding a new nginx config is enough, we have to go back to the current Bitbucket installation and make modifications to /var/atlassian/application-data/bitbucket/shared/bitbucket.properties which was modified during our initial install. We had prepared the original properties file already to make it easier to change after install by simply uncommenting those settings.
# run behind nginx ssl
#server.port=7990
#server.secure=true
#server.scheme=https
#server.proxy-port=443
#server.proxy-name=bitbucket.acme.com
As this is contained within the docker volume, we need yet again another process.
version: '3.3'
services:
bitbucket-proxy-init:
image: infra/atlassian/bitbucket-proxy-init:1.0.0
build:
context: .
network: host
args:
ARG_ART_URL: http://d1i-doc-ngbuild:3001
extra_hosts:
- "d1i-doc-ngbuild:172.22.90.2"
FROM infra/ubuntu/focal:1.0.0
ARG ARG_ART_URL
RUN sed -e "s|APT_URL|${ARG_ART_URL}|" /etc/apt/sources.list.base > /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y dos2unix \
&& apt-get clean \
&& rm /etc/apt/sources.list
COPY init.sh /init/init.sh
RUN chmod +x /init/init.sh \
&& dos2unix /init/init.sh
ENTRYPOINT ["/init/init.sh"]
#!/bin/bash
# fail if anything errors
set -e
# move it to backup
mv /var/atlassian/application-data/bitbucket/shared/bitbucket.properties /var/atlassian/application-data/bitbucket/shared/bitbucket.properties.bak2
# uncomment
sed -e "s|#server|server|" /var/atlassian/application-data/bitbucket/shared/bitbucket.properties.bak2 > /var/atlassian/application-data/bitbucket/shared/bitbucket.properties
# output it again
echo "Proxy changes completed"
Running the update is done via the following compose file that connects the appropriate docker volume.
version: '3.3'
services:
bitbucket:
image: infra/atlassian/bitbucket-proxy-init:1.0.0
volumes:
- bitbucket-data:/var/atlassian/application-data/bitbucket
networks:
- ops-network
networks:
ops-network:
name: ops-network
volumes:
bitbucket-data:
name: bitbucket-data
Build and run.
docker-compose -f images/bitbucket-proxy-init/docker-compose.yml build
docker-compose -f composed/docker-compose-bitbucket-proxy-init.yml up
Adding Bitbucket to Our CI/CD Apps
At this point we are already running several containers. Those are nginx-build, nginx for ssl, nexus, database. We will be adding bitbucket that is now fully configured via the following compose.
version: '3.3'
services:
bitbucket:
image: infra/atlassian/bitbucket:1.0.0
volumes:
- bitbucket-data:/var/atlassian/application-data/bitbucket
ports:
- 7990:7990
- 7999:7999
hostname: d1i-doc-bitbucket01
networks:
- ops-network
networks:
ops-network:
name: ops-network
volumes:
bitbucket-data:
name: bitbucket-data
We will be reusing the nginx we are running for nexus and using a new compose that combines both nexus and bitbucket.
server {
listen *:443 ssl;
server_name "nexus.acme.com";
ssl_certificate /etc/nginx/external/cert.pem;
ssl_certificate_key /etc/nginx/external/key.pem;
client_max_body_size 1G;
location / {
proxy_pass http://d1i-doc-nexus01:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
server {
listen *:443 ssl;
server_name "docker.acme.com";
ssl_certificate /etc/nginx/external/cert.pem;
ssl_certificate_key /etc/nginx/external/key.pem;
client_max_body_size 1G;
location / {
proxy_pass http://d1i-doc-nexus01:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
server {
listen *:443 ssl;
server_name "docker-private.acme.com";
ssl_certificate /etc/nginx/external/cert.pem;
ssl_certificate_key /etc/nginx/external/key.pem;
client_max_body_size 1G;
location / {
proxy_pass http://d1i-doc-nexus01:8083;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
server {
listen *:443 ssl;
server_name "bitbucket.acme.com";
ssl_certificate /etc/nginx/external/cert.pem;
ssl_certificate_key /etc/nginx/external/key.pem;
client_max_body_size 1G;
location / {
proxy_pass http://d1i-doc-bitbucket01:7990;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
version: '3.3'
services:
nginx:
image: infra/nginx/base:1.0.0
volumes:
- ./ssl/cert.pem:/etc/nginx/external/cert.pem
- ./ssl/key.pem:/etc/nginx/external/key.pem
- ./nginx/nexus.conf:/etc/nginx/conf.d/nexus.conf
- ./nginx/bitbucket.conf:/etc/nginx/conf.d/bitbucket.conf
ports:
- 443:443
hostname: d1i-doc-ng01
networks:
ops-network:
ipv4_address: 172.22.90.1
networks:
ops-network:
name: ops-network
driver: bridge
ipam:
driver: default
config:
- subnet: 172.22.90.0/16
Add our bitbucket container to the running containers and also add a new nginx config to run behind the same nginx instance.
# now start it up so we can put it behind nginx
docker-compose -f composed/docker-compose-bitbucket.yml up --no-start
docker-compose -f composed/docker-compose-bitbucket.yml start
# stop the nexusnginx and start the combined one
docker-compose -f composed/docker-compose-nginx-nexus.yml stop
docker-compose -f composed/docker-compose-nginx-nexus-bitbucket.yml up --no-start
docker-compose -f composed/docker-compose-nginx-nexus-bitbucket.yml start
We now have both Nexus and Bitbucket running via SSL behind our nginx.