{"id":621,"date":"2023-04-20T00:11:19","date_gmt":"2023-04-19T16:11:19","guid":{"rendered":"https:\/\/codestrian.com\/?p=621"},"modified":"2024-11-21T14:07:56","modified_gmt":"2024-11-21T06:07:56","slug":"running-gitlab-runner-in-a-container-and-use-it-to-build-and-upload-image","status":"publish","type":"post","link":"https:\/\/codestrian.com\/index.php\/2023\/04\/20\/running-gitlab-runner-in-a-container-and-use-it-to-build-and-upload-image\/","title":{"rendered":"Running Gitlab runner in a container and using it to build and upload image"},"content":{"rendered":"<p>Running GitLab Runner in a Docker container can be a great way to isolate your build environment and easily deploy your runners to different machines. Here are the steps to set up GitLab Runner in a Docker container:<\/p>\n<h3>Run the gitlab runner in a container<\/h3>\n<ol>\n<li>Create a docker volume to store the gitlab runner config\n<pre><code>docker volume create gitlab_runner_config<\/code><\/pre>\n<\/li>\n<li>Start the runner\n<pre><code>docker run -d --name gitlab-runner --restart always -v $XDG_RUNTIME_DIR\/docker.sock:\/var\/run\/docker.sock -v gitlab_runner_config:\/etc\/gitlab-runner gitlab\/gitlab-runner:latest<\/code><\/pre>\n<p>In the command shown above, the Docker socket is mounted to the container to enable the GitLab Runner to generate additional containers while executing the job. If you're using a rootful Docker, you can use <code>\/var\/run\/docker.sock<\/code>, but since I'm using a rootless Docker, the <code>XDG_RUNTIME_DIR<\/code> is defined on my machine. Additionally, we attach a named volume that we created earlier, which will store the configurations that are automatically generated by the runner upon registration.<\/p>\n<\/li>\n<\/ol>\n<h3>Register the gitlab runner<\/h3>\n<pre><code>docker run --rm -it -v gitlab_runner_config:\/etc\/gitlab-runner gitlab\/gitlab-runner:latest register -n \\\n --url https:\/\/your.gitlab.url\/ \\\n --registration-token &lt;GITLAB_TOKEN&gt;\\\n --executor docker \\\n --description &lt;Enter your description&gt; \\\n --docker-image &quot;docker:23.0.3-cli&quot; \\\n --docker-privileged \\\n --docker-volumes gitlab_certs_client:\/certs\/client \\\n --tag-list &lt;Enter your tag list&gt;\n<\/code><\/pre>\n<ul>\n<li>\n<p><strong>docker run<\/strong>: This starts a new Docker container.<\/p>\n<\/li>\n<li>\n<p><strong>--rm<\/strong>: This option automatically removes the container after it exits.<\/p>\n<\/li>\n<li>\n<p><strong>-it<\/strong>: This option allocates a pseudo-TTY and opens an interactive terminal.<\/p>\n<\/li>\n<li>\n<p><strong>-v<\/strong> gitlab-runner-config:\/etc\/gitlab-runner: This mounts a named volume named &quot;gitlab-runner-config&quot; to the \/etc\/gitlab-runner directory in the container. This allows the container to access the GitLab Runner configuration file.<\/p>\n<\/li>\n<li>\n<p><strong>gitlab\/gitlab-runner:latest<\/strong>: This specifies the GitLab Runner Docker image to use.<\/p>\n<\/li>\n<li>\n<p><strong>register<\/strong>: This tells the GitLab Runner to register itself with the GitLab server.<\/p>\n<\/li>\n<li>\n<p><strong>-n<\/strong>: This option specifies that the runner should not perform any builds automatically after registration.<\/p>\n<\/li>\n<li>\n<p><strong>--url<\/strong> <a href=\"https:\/\/your.gitlab.url\/\">https:\/\/your.gitlab.url\/<\/a>: This specifies the URL of the GitLab instance to register the runner with.<\/p>\n<\/li>\n<li>\n<p><strong>--registration-token<\/strong> <GITLAB_TOKEN>: This specifies the registration token to use. You can obtain this token from your GitLab instance.<\/p>\n<\/li>\n<li>\n<p><strong>--executor docker<\/strong>: This specifies that the GitLab Runner should use Docker as its execution environment.<\/p>\n<\/li>\n<li>\n<p><strong>--description <Enter your description><\/strong>: This allows you to enter a description for the runner.<\/p>\n<\/li>\n<li>\n<p><strong>--docker-image &quot;docker:23.0.3-cli&quot;<\/strong>: This specifies the Docker image to use for running the build.<\/p>\n<\/li>\n<li>\n<p><strong>--docker-privileged<\/strong>: This enables privileged mode for the Docker container.<\/p>\n<\/li>\n<li>\n<p><strong>--docker-volumes gitlab_certs_client:\/certs\/client<\/strong>: This mounts a named volume named &quot;gitlab_certs_client&quot; to the \/certs\/client directory in the container. This allows the service and build container to communicate with one another with TLS.<\/p>\n<\/li>\n<li>\n<p><strong>--tag-list<\/strong> <Enter your tag list>: This allows you to specify any tags to assign to the runner.<\/p>\n<\/li>\n<\/ul>\n<p>To build an docker image, here is an example of the <code>.gitlab-ci.yml<\/code><\/p>\n<pre><code>variables:\n  DOCKER_TLS_CERTDIR: &quot;\/certs&quot;\n\nservices:\n  - docker:23.0.3-dind\n\nbuild:\n  stage: build\n  script:\n    - docker build -t my-docker-image .\n    - docker run my-docker-image \/script\/to\/run\/tests<\/code><\/pre>\n<p>To utilize the official Docker Hub registry for pulling and pushing images, simply modify the aforementioned example. For those, like myself, who employ a private Docker registry, additional configuration steps are necessary.<\/p>\n<h2>Configuration for Docker-in-Docker<\/h2>\n<p>As TLS is in use, it is essential to direct Docker to employ the correct CA certificate when connecting to the private registry; failing to do so may result in an x509: certificate signed by unknown authority error.<\/p>\n<p>Let\\'s first create a docker volume to hold the docker daemon configurations for the dind container.<\/p>\n<pre><code>docker volume create gitlab_runner_docker_config<\/code><\/pre>\n<p>Next, navigate to the newly created directory and create a <code>daemon.json<\/code> file with the following content.<\/p>\n<pre><code>{\n  &quot;registry-mirrors&quot;: [\n    &quot;https:\/\/registry-mirror.example.com:28000&quot;\n  ]\n}<\/code><\/pre>\n<p>Within the same directory create a directory in this format <code>cert.d\/&lt;registry.url&gt;:&lt;port&gt;<\/code> to hold the CA certificate.<\/p>\n<pre><code>mkdir -p cert.d\/registry-mirror.example.com:28000<\/code><\/pre>\n<p>Next, copy your CA certificate to the newly created directory.<\/p>\n<p>Proceed to update the <code>config.toml<\/code> file located in the <code>gitlab_runner_config<\/code> directory. Within <code>config.toml<\/code>, add the <code>gitlab_runner_docker_config<\/code> to the volumes parameter.<\/p>\n<pre><code>concurrent = 1\ncheck_interval = 0\nshutdown_timeout = 0\n\n[session_server]\n  session_timeout = 1800\n\n[[runners]]\n  name = &quot;gitlab runner docker executor&quot;\n  url = &quot;https:\/\/your.gitlab.url\/&quot;\n  id = 1\n  token = &quot;TOKEN&quot;\n  token_obtained_at = 2023-04-17T05:42:11Z\n  token_expires_at = 0001-01-01T00:00:00Z\n  executor = &quot;docker&quot;\n\n  [runners.cache]\n    MaxUploadedArchiveSize = 0\n  [runners.docker]\n    tls_verify = false\n    image = &quot;docker:23.0.3-cli&quot;\n    privileged = true\n    disable_entrypoint_overwrite = false\n    oom_kill_disable = false\n    disable_cache = false\n    volumes = [\n      &quot;gitlab_runner_docker_config:\/etc\/docker&quot;,\n      &quot;gitlab_certs_client:\/certs\/client&quot;,\n      &quot;\/cache&quot;\n    ]\n    shm_size = 0\n<\/code><\/pre>\n<p>Reload the gitlab runner configuration by executing the following command in your gitlab runner container<\/p>\n<pre><code>gitlab-runner restart<\/code><\/pre>\n<p>After implementing the changes, the updated Docker daemon configurations will be available within the Docker-in-Docker (dind) containers as they run. However, there is one more step: guiding the Docker daemon to log into the private registry.<\/p>\n<pre><code>build:\n  before_script:\n    - echo &quot;$DOCKER_REGISTRY_PASS&quot; | docker login $DOCKER_REGISTRY --username $DOCKER_REGISTRY_USER --password-stdin<\/code><\/pre>\n<p>Now you should be able to build, pull and push images within your gitlab runner using docker-in-docker image.<\/p>\n<h2>What if you are using a self-hosted gitlab?<\/h2>\n<p>If you are using a self-hosted gitlab like me, you will need update the CA certificate on the default docker job container and the dind service container.<\/p>\n<p>Add the following <code>pre_build_script<\/code> into <code>config.toml<\/code> which will update the ca-certificate within the dind container. (Modify the script if you are using a Ubuntu based dind image)<\/p>\n<pre><code>pre_bulid_script = &quot;&quot;&quot;\n  apk update &gt;\/dev\/null\n  apk add ca-certificates &gt; \/dev\/null\n  cp \/etc\/gitlab-runner\/certs\/ca.crt \/usr\/local\/share\/ca-certificates\/ca.crt\n  update-ca-certificates --refresh &gt; \/dev\/null\n&quot;&quot;&quot;<\/code><\/pre>\n<p>Next, we need to ensure that the <code>ca.crt<\/code> is available at <code>\/etc\/gitlab-runner\/certs<\/code>. To achieve that , we ill need to mount a new volume in <code>config.toml<\/code><\/p>\n<pre><code>volumes = [\n  ...\n  &quot;\/path\/to\/your\/ca.crt:\/etc\/gitlab-runner\/certs\/ca.crt:ro&quot;,\n  ...\n]<\/code><\/pre>\n<p>Your final <code>config.toml<\/code> may look like this.<\/p>\n<pre><code>concurrent = 1\ncheck_interval = 0\nshutdown_timeout = 0\n\n[session_server]\n  session_timeout = 1800\n\n[[runners]]\n  name = &quot;gitlab runner docker executor&quot;\n  url = &quot;https:\/\/your.gitlab.url\/&quot;\n  id = 6\n  token = &quot;TOKEN&quot;\n  token_obtained_at = 2023-04-17T05:42:11Z\n  token_expires_at = 0001-01-01T00:00:00Z\n  executor = &quot;docker&quot;\n  pre_build_script = &quot;&quot;&quot;\n    apk update &gt;\/dev\/null\n    apk add ca-certificates &gt; \/dev\/null\n    rm -rf \/var\/cache\/apk\/*\n    cp \/etc\/gitlab-runner\/certs\/ca.crt \/usr\/local\/share\/ca-certificates\/ca.crt\n    update-ca-certificates --fresh &gt; \/dev\/null\n    mkdir -p \/etc\/docker\/certs.d\/registry-mirror.example.com:28000\n    cp \/etc\/gitlab-runner\/certs\/ca.crt \/etc\/docker\/certs.d\/registry-mirror.example.com:28000\/ca.crt\n  &quot;&quot;&quot;\n\n  [runners.cache]\n    MaxUploadedArchiveSize = 0\n  [runners.docker]\n    tls_verify = false\n    image = &quot;docker:23.0.3-cli&quot;\n    privileged = true\n    disable_entrypoint_overwrite = false\n    oom_kill_disable = false\n    disable_cache = false\n    volumes = [\n      &quot;gitlab_runner_docker_config:\/etc\/docker&quot;,\n      &quot;gitlab_certs_client:\/certs\/client&quot;,\n      &quot;\/home\/docker\/.docker\/certs\/internal-ca.crt:\/etc\/gitlab-runner\/certs\/ca.crt:ro&quot;,\n      &quot;\/cache&quot;\n    ]\n    shm_size = 0\n<\/code><\/pre>\n<p>Lastly, make sure that the CA cert is copied to your <code>\/path\/to\/docker\/volumes\/gitlab_runner_config\/_data\/certs\/<\/code> and named as <code>ca.crt<\/code>.<\/p>\n<p>Restart your gitlab runner and your pipeline should be working smoothly now.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/codestrian.com\/wp-content\/uploads\/2023\/04\/gitlab_success-1024x92.png\" alt=\"\" \/><\/p>\n<h2>References<\/h2>\n<p><a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/docker\/using_docker_build.html\">https:\/\/docs.gitlab.com\/ee\/ci\/docker\/using_docker_build.html<\/a><br \/>\n<a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/docker\/authenticate_registry.html\">https:\/\/docs.gitlab.com\/ee\/ci\/docker\/authenticate_registry.html<\/a><br \/>\n<a href=\"https:\/\/docs.gitlab.com\/ee\/ci\/yaml\/\">https:\/\/docs.gitlab.com\/ee\/ci\/yaml\/<\/a><br \/>\n<a href=\"https:\/\/docs.gitlab.com\/runner\/configuration\/tls-self-signed.html\">https:\/\/docs.gitlab.com\/runner\/configuration\/tls-self-signed.html<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Running GitLab Runner in a Docker container can be a great way to isolate your build environment and easily deploy your runners to different machines. Here are the steps to set up GitLab Runner in a Docker container: Run the gitlab runner in a container Create a docker volume to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[62],"tags":[73,13,43],"_links":{"self":[{"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/posts\/621"}],"collection":[{"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/comments?post=621"}],"version-history":[{"count":9,"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/posts\/621\/revisions"}],"predecessor-version":[{"id":631,"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/posts\/621\/revisions\/631"}],"wp:attachment":[{"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/media?parent=621"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/categories?post=621"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codestrian.com\/index.php\/wp-json\/wp\/v2\/tags?post=621"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}