diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0fc3028d9fa75b15150c9ce1ce0f78d55e7a7075
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,64 @@
+stages:
+  - test
+  - build_docker
+  - build_pip
+
+.python_job:
+  image: python:3.11
+  before_script:
+    - pip install poetry
+    - poetry install
+    - source `poetry env info --path`/bin/activate
+
+testing:
+  extends: .python_job
+  stage: test
+  rules:
+  - if: '$CI_COMMIT_BRANCH == "stable"'
+  - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "stable"'
+  - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"'
+  script:
+    - cd tests
+    - poetry run pytest --junitxml=report.xml
+  artifacts:
+    when: always
+    reports:
+      junit: /builds/PA/collective-effects/mbtrack2/tests/report.xml
+
+formatters:
+  extends: .python_job
+  stage: test
+  rules:
+  - if: '$CI_COMMIT_BRANCH == "stable"'
+  - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "stable"'
+  - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"'
+  script:
+    - poetry run isort --check --diff mbtrack2/
+    - poetry run yapf -d -r mbtrack2/
+
+docker:
+  stage: build_docker
+  rules:
+    - if: '$CI_COMMIT_TAG'
+  image: docker:latest
+  services:
+    - docker:dind
+  variables:
+    CONTAINER_RELEASE_IMAGE: ${CI_REGISTRY_IMAGE}:latest
+    CONTAINER_TAG_IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}
+  script:
+    - echo "${CI_REGISTRY_PASSWORD}" | docker login -u ${CI_REGISTRY_USER} --password-stdin ${CI_REGISTRY}
+    - docker build --pull -t ${CONTAINER_RELEASE_IMAGE} .
+    - docker image tag ${CONTAINER_RELEASE_IMAGE} ${CONTAINER_TAG_IMAGE}
+    - docker push ${CONTAINER_RELEASE_IMAGE}
+    - docker push ${CONTAINER_TAG_IMAGE}
+
+pip:
+  extends: .python_job
+  stage: build_pip
+  rules:
+    - if: '$CI_COMMIT_TAG'
+  script:
+    - poetry config repositories.gitlab ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi
+    - poetry build
+    - poetry publish --repository gitlab -u gitlab-ci-token -p ${CI_JOB_TOKEN}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..514a39f1afb10247afca86ee5ab839f82103daff
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,35 @@
+FROM ubuntu:22.04
+RUN useradd -s /bin/bash dockeruser
+LABEL name mbtrack2
+RUN apt-get update
+RUN apt-get install -y sudo
+RUN adduser dockeruser sudo
+RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
+USER dockeruser
+WORKDIR '/home/dockeruser'
+RUN sudo -E apt-get update
+RUN sudo -E apt-get install -y git && \
+    sudo -E apt-get install -y wget && \
+    sudo -E apt-get install -y gcc g++ &&\
+    sudo -E apt-get install -y gfortran &&\
+    sudo -E apt-get install -y make
+
+RUN wget \
+    https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \
+    && bash Miniconda3-latest-Linux-x86_64.sh -b \
+    && rm -f Miniconda3-latest-Linux-x86_64.sh \
+    && eval "$(/home/dockeruser/miniconda3/bin/conda shell.bash  hook)"\
+    && conda init
+ 
+ENV PATH ${PATH}:/home/dockeruser/miniconda3/bin:/home/dockeruser/miniconda3/condabin
+RUN conda config --add channels conda-forge
+RUN conda install -y gcc_linux-64 gxx_linux-64 gfortran_linux-64
+RUN conda install -y mpi=1.0=openmpi
+RUN conda install -y hdf5=1.14.2=mpi_openmpi_h327c9cf_0
+RUN conda install -y "python=3.11.*" numpy scipy matplotlib mpi4py "h5py>=2.9=mpi*" pandas pip seaborn mpmath
+RUN pip3 install accelerator-toolbox
+
+# Copy and install
+COPY --chown=dockeruser mbtrack2 /home/dockeruser/mbtrack2
+
+ENV PYTHONPATH=/home/dockeruser/
\ No newline at end of file