Have you ever been tasked with pipelining out an existing application in a new tool? This can be a long and daunting task. Especially if your application is multi-service, and mono-repo. I’m not going to get into all of hows and whys of multi-repo vs mono-repo today, but there is always a use case or operational model for each.
One of the biggest issues I have run into with multi-serivce mono-repo apps is getting the container builds to work the first time. In fact, I generally fail the first time. Miserably.
Why is this? If we take a look at the error message that was received, it states that it can’t find the Dockerfile.
Long story short here, there is some kind of working-direcotry issue. When working with different CI/CD Pipeline tools, they each have their own runtime-environment or runner. This is the environment process that actually does the work. Some of them handle working-direcotires in different ways. All we have to do to fix this problem is figure out the working directory structure and handle accordingly. Let’s look at the example of the codefresh YAML file. I took the default build step and edited it to be a multi-step build and pointed it to the directory structure of the repo for the appropriate Dockerfile.
build:cart: title: "Build Cart Service" type: "build" image_name: "cart" working_directory: '.' tag: 'master' dockerfile: /app/cart/Dockerfile
Our apps repository has all of the multiple services in their own sub-folders under the /app directory at the root of the repo. Based on our error, it seems that the codefresh runtime environment does not execute from the base of the repository by default. This isn’t a problem. When you clone a Git repo into a linux machine, you then have to CD into the directory. Based on this knowledge, we should be able to fix this issue simply by appending the repo name to the front of the path to the Dockerfile:
build:cart: title: "Build Cart Service" type: "build" image_name: "cart" working_directory: '.' tag: 'master' dockerfile: acme_fitness/app/cart/Dockerfile
It worked! Except, now we’re left with another issue. There is now an issue with the docker build finding the requirements.txt file. Let’s take a look at the Dockerfile to see what’s going on here:
FROM bitnami/python:3.7 MAINTAINER Developer "email@example.com" ENV REDIS_HOST="localhost" ENV REDIS_PORT="6379" ENV REDIS_PASSWORD="" # needed for redis-cli ; the server is not used RUN install_packages redis-server COPY ./app/cart/requirements.txt /app/requirements.txt RUN pip3 install -r requirements.txt ADD . /app COPY /app/cart/entrypoint/docker-entrypoint.sh /usr/local/bin/ RUN chmod 777 /usr/local/bin/docker-entrypoint.sh RUN ln -s /usr/local/bin/docker-entrypoint.sh /app # backwards compat EXPOSE 80 EXPOSE 5000 ENTRYPOINT ["docker-entrypoint.sh"]
Obviously, this dockerfile was built assuming you were working from the root of the repo. We can yet again make some alterations here so that the actual working-directory can read-through to the correct file location:
FROM bitnami/python:3.7 MAINTAINER Developer "firstname.lastname@example.org" ENV REDIS_HOST="localhost" ENV REDIS_PORT="6379" ENV REDIS_PASSWORD="" # needed for redis-cli ; the server is not used RUN install_packages redis-server COPY acme_fitness/app/cart/requirements.txt /app/requirements.txt RUN pip3 install -r requirements.txt ADD . acme_fitness/app COPY acme_fitness/app/cart/entrypoint/docker-entrypoint.sh /usr/local/bin/ RUN chmod 777 /usr/local/bin/docker-entrypoint.sh RUN ln -s /usr/local/bin/docker-entrypoint.sh /app # backwards compat EXPOSE 80 EXPOSE 5000 ENTRYPOINT ["docker-entrypoint.sh"]
Let’s see what happens now when we run the pipeline:
Success! While we had to do some re-working of the files associated with the app, they were very minimal. All you need to do to extend this to the other services, is to setup their Dockerfile accordingly for the working directory. Now, there is also multiple ways you can do this, and not all pipeline tools are the same, but this is a quick fix to get your builds running in Codefresh.
I would like to put a small disclaimer here, whenever you are going in and making changes to the core files of your app, always clone or fork the repo. Don’t make a bunch of sweeping changes to the master repo of the prod code. But, I’m sure you already knew that. Happy Pipelining!
Cloud and Developer Advocate