# Question
Title: No longer see Docker build output properly!
I am using the latest version of Docker Desktop on Windows (**Docker Engine version v19.03.13**).

After the last update, the output of `docker build .` has changed! *It is now harder to debug what is going on*.

Here is my `Dockerfile`:

```
# set base image as the dotnet 3.1 SDK.
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env

# set the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD
# instructions that follows the WORKDIR instruction.
WORKDIR /app

# debug purposes - see where we are
RUN pwd

# our current working directory within the container is /app
# we now copy all the files (from local machine) to /app (in the container).
COPY . ./

# debug purposes - list files in current folder
RUN ls -la

# run unit tests within the solution.
RUN dotnet test Phoneden.sln

# again, on the container (we are in /app folder)
# we now publish the project into a folder called 'out'.
RUN dotnet publish Phoneden.Web/Phoneden.Web.csproj -c Release -o out

# debug purposes - list files in current folder
RUN ls -la

# set base image as the dotnet 3.1 runtime.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS runtime

# telling the application what port to run on.
ENV ASPNETCORE_URLS=http://*:5005

# set the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD
# instructions that follows the WORKDIR instruction.
WORKDIR /app

# copy the contents of /app/out in the `build-env` and paste it in the
# `/app` directory of the new runtime container.
COPY --from=build-env /app/Phoneden.Web/out .

# set the entry point into the application.
ENTRYPOINT ["dotnet", "Phoneden.Web.dll", "-seed"]

```

When I run `docker build --no-cache .` I get the following:

```
jwan@home-desktop MSYS /c/code/phoneden (upgrade/net-3.1)
$ docker build --no-cache .
[+] Building 38.9s (16/16) FINISHED
 => [internal] load .dockerignore                                                                                0.1s
 => => transferring context: 35B                                                                                0.0s
 => [internal] load build definition from Dockerfile                                                                                0.0s
 => => transferring dockerfile: 32B                                                                                0.0s
 => [internal] load metadata for mcr.microsoft.com/dotnet/core/aspnet:3.1                                                                                0.0s
 => [internal] load metadata for mcr.microsoft.com/dotnet/core/sdk:3.1                                                                                0.0s
 => [internal] load build context                                                                                0.3s
 => => transferring context: 96.50kB                                                                                0.2s
 => [build-env 1/8] FROM mcr.microsoft.com/dotnet/core/sdk:3.1@sha256:1d96e460ac4af00ffc41c5d4a27b503f2589098c84b6ca10d09e0f7ef6e31689                                                                                0.0s
 => [runtime 1/3] FROM mcr.microsoft.com/dotnet/core/aspnet:3.1@sha256:41ece4e6218d5f2c66191c4bd8b8dda060ea3b1512353fe1185e239121458ab5                                                                                0.0s
 => CACHED [build-env 2/8] WORKDIR /app                                                                                0.0s
 => CACHED [runtime 2/3] WORKDIR /app                                                                                0.0s
 => [build-env 3/8] RUN pwd                                                                                0.3s
 => [build-env 4/8] COPY . ./                                                                                0.3s
 => [build-env 5/8] RUN ls -la                                                                                0.3s
 => [build-env 6/8] RUN dotnet test Phoneden.sln                                                                                17.7s
 => [build-env 7/8] RUN dotnet publish Phoneden.Web/Phoneden.Web.csproj -c Release -o out                                                                                19.5s
 => [build-env 8/8] RUN ls -la                                                                                0.6s
 => ERROR [runtime 3/3] COPY --from=build-env /app/Phoneden.Web/out .                                                                                0.0s
------
 > [runtime 3/3] COPY --from=build-env /app/Phoneden.Web/out .:
------
failed to solve with frontend dockerfile.v0: failed to build LLB: failed to compute cache key: "/app/Phoneden.Web/out" not found: not found

```

As you can see, it is not listing the result of the debug commands I added.

How can I get the output to be verbose like it was before the update?

# Answer
This is the output from buildkit. You can run buildkit based builds with a different output syntax:

```
$ docker build --help
...
  --progress string         Set type of progress output (auto, plain, tty). Use plain to show container output
                            (default "auto")

```

In your command, that would be:

```
docker build --progress=plain .

```

Or you can disable buildkit by setting `DOCKER_BUILDKIT=0` in your shell:

```
DOCKER_BUILDKIT=0 docker build .

```
> 12 votes

---
Tags: docker
---


# Question
Title: Using Docker images as vehicles for binary deployment artifacts
Let's say we're in an environment where we have a modern CI/CD pipeline for a number of containerized apps. We also have a number legacy apps which haven't been containerized yet.

I'm wondering how sound/unusual/crazy the following idea is: even for apps which don't run in containers in production, **use container images and a container registry as a vehicle to deploy binary build artifacts**.

Here's a very simple example to illustrate the idea: let's say we have a .NET app which consists of two projects. One that rarely changes and contains a large number of static assets (`ChangesRarely`), and another small, lightweight one which changes often (`ChangesOften`).

Now, let's say we're using the following `Dockerfile` to build the app in a multi-stage build:

```
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS builder
ADD src src
RUN dotnet publish -o buildOutput/ChangesRarely src/ChangesRarely
RUN dotnet publish -o buildOutput/ChangesOften src/ChangesOften

FROM alpine
COPY --from=builder buildOutput/ChangesRarely /buildOutput/ChangesRarely
COPY --from=builder buildOutput/ChangesOften /buildOutput/ChangesOften

```

Note that because of the two separate `COPY` instructions, the resulting image will contain two separate layers. This will be important in just a second.

When our CI/CD build system (e.g. GitHub Actions) needs to create a new build, it'll basically run `docker build -t myapp .` and push the resulting image to a container registry. So far, pretty standard.

Now let's say we want to deploy a new version to production. Again, "production" isn't some sort of container orchestrator (yet) - assume it's a set of plain old servers in a data center. So here's where the approach might become a tad unusual:

Each production server runs a Docker engine- but only to pull the container image and subsequently copy the build artifacts out of it, deploying them to their final destination (some local folder):

```
id=$(docker create myapp)                 # pulls image from container registry, if necessary
docker cp $id:/buildOutput - | tar zxf -  # copy build artifacts
docker rm -v $id                          # destroy temp container

```

I've confirmed that this really works. But, why would you do that? Three main reasons:

* The container registry acts as a unified store for all build artifacts (for containerized and non-containerized apps). No need to manage two different artifact stores.
* Image layers which are identical across builds (such as the large `ChangesRarely` layer in the example above) only need to be stored once in the container registry, preserving storage space
* They also will be cached by the production server's Docker engine, preserving network bandwidth and reducing deployment times.

How usual or unusual is this approach?

Any problems with the approach that I might be missing?

# Answer
> 2 votes
I've seen it done before but wouldn't call it common. There are other artifact servers, and many git repositories have the concept of a release with artifacts that makes more sense.

I suspect Docker Hub is one of many artifact servers to introduce rate limits and other usage caps, so if you do this, make sure you control (or pay for) the registry server. Otherwise the risk is you'll exceed limits and lose access to your artifacts.

If you only want to copy binaries, then I'd skip the base image and use `FROM scratch`.

It's also possible to bypass the docker engine entirely and pull the artifacts from the registry server directly to the filesystem. I have a regclient project that ships a `regctl` command with `regctl image manifest` and `regctl layer pull` commands. E.g.:

```
$ regctl image manifest regclient/regctl
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
  "config": {
    "mediaType": "application/vnd.docker.container.image.v1+json",
    "size": 3019,
    "digest": "sha256:e3abac7c7ce78aaa5efddb5abedd54f8ed3077d9d5b03b5a66ecf9f4c3502454"
  },
  "layers": [
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 930,
      "digest": "sha256:41437cd6a6e3d3098329474c62ccc5bd01fcf6b41bf35f0e8c89db96110b23ac"
    },
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 122413,
      "digest": "sha256:69d6afda22ccf4f223c016bfd3a108fe0a1ddd15c72978bd238b19201e0e1973"
    },
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 161,
      "digest": "sha256:57dd9736a25ab0b55d9d364dc20ee0946a844a8ac72d7f986ef902826f933e89"
    },
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 3963283,
      "digest": "sha256:282c5a3b4b6c8bf0b7038204919bbfc26c8b120cd87f4a1f573c12c808774c1c"
    }
  ]
}

$ regctl layer pull regclient/regctl sha256:282c5a3b4b6c8bf0b7038204919bbfc26c8b120cd87f4a1f573c12c808774c1c | tar -tzvf -
-rwxr-xr-x root/root  10235904 2020-11-05 20:52 regctl

```

Note that the sha's are unique and persistent, so if that hash is unchanged there's no need to pull the binary again. And the above example has a few extra layers since the command is expected to run in the image as a non-root user (/etc/passwd, ca-certificates, and a home directory). For a non-running image, that could be a single layer. E.g.:

```
# change image to your scratch-based source
image=regclient/regctl
store=/tmp
sha=$(regctl image manifest $image --format '{{ (index .Layers 0).Digest}}')
if [ ! -d "$store/$sha" ]; then
  mkdir -p "$store/$sha"
  regctl layer pull $image $sha | tar -xzvf - -C "$store/$sha"
fi
echo "result in $store/$sha"

```

---
Tags: docker, continuous-integration
---


# Question
Title: Cleanest way to prematurely exit a Jenkins Pipeline job as a success?
I have a job that will create files, unless one of the values being fed to it matches an older value. What's the cleanest way in Jenkins to abort or exit the job, **without** it being `FAILED`? It exiting is the correct behavior so I want the build marked `SUCCESS`.

It'll end up in an if statement like so;

```
stage ('Check value') {

     if( $VALUE1 == $VALUE2 ) {
       //if they do match exit as a success, else continue with the rest of the job
    }

}

```

I don't want to throw an error code unless that can somehow translate into it being marked a successful build.

# Answer
Please note: The following works for scripted pipelines only. For a solution for declarative pipelines see @kgriffs' answer.

---

Figured it out. **Outside of any stages** (otherwise this will just end the particular stage as a success) do the following;

```
if( $VALUE1 == $VALUE2 ) {
   currentBuild.result = 'SUCCESS'
   return
}

```

`return` **will stop the stage or node you're running on** which is why running it outside of a stage is important, while setting the `currentBuild.result` prevents it from failing.
> 96 votes

# Answer
The `Executor.interrupt(Result)` method is the cleanest, most direct way I could find to stop a build prematurely *and* mark it as a success.

```
script {
    currentBuild.getRawBuild().getExecutor().interrupt(Result.SUCCESS)
    sleep(1)   // Interrupt is not blocking and does not take effect immediately.
}

```

**Pros**:

* Works in a declarative pipeline just as well as a scripted one.
* No try/catch or exceptions to handle.
* Marks the calling stage and any successive stages as green/passing in the UI.

**Cons**:

* Requires a number of in-process script approvals, including one that is considered insecure. Approve and use with caution.
> 25 votes

# Answer
You can also use error to exit the current stage, then you don't have to consider the current stage hierarchy and similar stuff:

```
def autoCancelled = false

try {
  stage('checkout') {
    ...
    if (your condition) {
      autoCancelled = true
      error('Aborting the build.')
    }
  }
} catch (e) {
  if (autoCancelled) {
    currentBuild.result = 'SUCCESS'
    // return here instead of throwing error to keep the build "green"
    return
  }
  // normal error handling
  throw e
}

```

But this would lead to a red stage, if the error occurs within a stage.

It depends on your requirements, which way you want to use.
> 21 votes

# Answer
If it is acceptable to set the build status to `ABORTED` instead of `SUCCESS`, the following snippet may be used within a pipeline stage to short-circuit the build:

```
steps {
    script {
        currentBuild.result = 'ABORTED'
        error("Aborting the build.")
    }
}

```

I tested setting the result to `SUCCESS`, but doing so resulted in a failed build (using Jenkins 2.235.5). It seems that `ABORTED` is respected by the `error` step, while `SUCCESS` is overridden.
> 13 votes

# Answer
I was *almost* able to accomplish this with declarative pipeline. This allows you to exit the before the pipeline starts based on the outcome of a shell script. I was not able to get this working within the pipeline itself (either within or between stages).

```
node('master'){
    env.status_code = sh(script: 'exit 0 # or 200 or other', returnStatus:true)
}
println 'status_code: ' + env.status_code
if(env.status_code == '200'){
    println 'Now is not the time to run the pipeline.'
    println 'Exiting without running subsequent stages.'
    currentBuild.result = 'SUCCESS'
    return
} else if(env.status_code == '0'){
    println 'Time to run. Let\'s go!'
} else {
    error 'Unable to check if it\'s time to run.'
}

pipeline {
  agent any
  stages {
      stage('Run only if exit status for was 0'){
          steps{
             sh 'echo hi'
          }
      }
  }
}

```

`when` directive may help if you only want to skip certain stages, not exit entirely.

https://www.jenkins.io/doc/book/pipeline/syntax/#when
> 3 votes

# Answer
Honestly you shouldn't need to use the `exit` command specifically, but there is a Conditional BuildStep Plugin which may achieve the same end result (code that doesn't run).

I haven't come up against this yet, so haven't used the plugin.

There is also conditionals as found in this prior Stack Overflow post on Jenkins: Jenkins Pipeline Conditional Step/Stage
> 1 votes

---
Tags: jenkins, jenkins-pipeline, groovy
---


# Question
Title: Getting a 502 Bad Server Request on Nginx
I'm trying run the frontend (`react`) and a backend (`nodejs,` express`) from a same` ubuntu 20.4\` machine but for some reason my nginx is not mapping correctly. I don't know if I have a typo somewhere or just configured something wrong?

Inside `/etc/nginx/sites-enabled/` I have created 2 files one for the `frontend` and one for the `backend`

The contents inside the `backend` file are the following:

```
 server {
    # server_name  ## add server name
      server_name  backend.develop.mysite.be; // Dummy name for SO, but actual file contains the right address

    location / {
        proxy_read_timeout 1800;
        proxy_connect_timeout 1800;
        proxy_send_timeout 1800;
        send_timeout 1800;

      proxy_pass http://localhost:9000;  // [ASK]: Is this is what is causing the problem? Maybe I should change it to 3000 ?
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection 'upgrade';
      proxy_set_header Host $host;
      proxy_cache_bypass $http_upgrade;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/frontend.develop.mysite.be/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/frontend.develop.mysite.be/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
 server {
    if ($host = backend.develop.mysite.be) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
      server_name  backend.develop.mysite.be;
    return 404; # managed by Certbot

}

```

the contents for the `frontend` are very similar just with a different name. In the past this setup worked for me, but for some reason right now I'm getting a `502 BAD Gateway` response error but only for the `backend`. The `frontend` seems to work just fine.

# Answer
Never mind, I just figured it out . I just needed to change the port i was refering inside the `backend` file `/etc/nginx/sites-enabled/backend`

Changed this line `proxy_pass http://localhost:9000;` to this line `proxy_pass http://localhost:3000;` and it worked.
> 0 votes

---
Tags: nginx, node.js, ubuntu
---


# Question
Title: invalid base hashes in `extends` with 'include' -- gitlab-ci
I have a huge .gitlab-ci.yml file that I am trying to turn into the "main" ci file by moving some parts to another files which will then be called with the use of the "include" keyword.

.gitlab-ci.yml file:

```
image: golang:latest

stages:
  - validate

include: /.gitlab/ci/_common.gitlab-ci.yml

validate:
  stage: validate
  extends: .gitlab-tf-backend
  before_script:
    - cd ${TF_ROOT}
    - terraform init -backend=false
    - mv $CI_PROJECT_DIR/deployment.zip .
  script:
    - terraform validate
    - terraform fmt -check=true
  only:
    - branches

```

.gitlab/ci/\_common.gitlab-ci.yml file:

```
variables:
  GITLAB_API_ENDPOINT: https://gitlab.com/api/v4
  TF_ROOT: ${CI_PROJECT_DIR}/terraform
  PLAN: plan.tfplan
  JSON_PLAN_FILE: tfplan.json
  GIT_DEPTH: 10

.gitlab-tf-backend: &gitlab-tf-backend
   - export TF_ADDRESS=${GITLAB_API_ENDPOINT}/projects/${CI_PROJECT_ID}/terraform/state/${STATE_NAME}
   - export TF_HTTP_ADDRESS=${TF_ADDRESS}
   - export TF_HTTP_LOCK_ADDRESS=${TF_ADDRESS}/lock
   - export TF_HTTP_LOCK_METHOD=POST
   - export TF_HTTP_UNLOCK_ADDRESS=${TF_ADDRESS}/lock
   - export TF_HTTP_UNLOCK_METHOD=DELETE
   - export TF_HTTP_USERNAME=${USERNAME}
   - export TF_HTTP_PASSWORD=${GITLAB_TOKEN}
   - export TF_HTTP_RETRY_WAIT_MIN=5
   - echo "Using HTTP Backend at $TF_HTTP_ADDRESS"
   - terraform --version
   - terraform init

```

My file is correctly found by gitlab. It seems that my hidden job ".gitlab-tf-backend" is not recognized and cannot be called.

Full error is:

```
This GitLab CI configuration is invalid: validate: invalid base hashes in `extends` (.gitlab-tf-backend)

```

How could I properly call my '.gitlab-tf-backend' hidden job from my main .gitlab-ci.yml file ?

# Answer
> 2 votes
Okay, found it.

It seems the .gitlab-ci.yml hidden job needs to have a "script:" to solve the problem. See below:

```
.gitlab-tf-backend: &gitlab-tf-backend
      script:
       - export TF_ADDRESS=${GITLAB_API_ENDPOINT}/projects/${CI_PROJECT_ID}/terraform/state/${STATE_NAME}
       - export TF_HTTP_ADDRESS=${TF_ADDRESS}
       - export TF_HTTP_LOCK_ADDRESS=${TF_ADDRESS}/lock
       - export TF_HTTP_LOCK_METHOD=POST
       - export TF_HTTP_UNLOCK_ADDRESS=${TF_ADDRESS}/lock
       - export TF_HTTP_UNLOCK_METHOD=DELETE
       - export TF_HTTP_USERNAME=${USERNAME}
       - export TF_HTTP_PASSWORD=${GITLAB_TOKEN}
       - export TF_HTTP_RETRY_WAIT_MIN=5
       - echo "Using HTTP Backend at $TF_HTTP_ADDRESS"
       - terraform --version
       - terraform init

```

---
Tags: continuous-integration, gitlab, yaml
---


# Question
Title: Create backend Address pool for basic load balancer azure arm template
I'm attempting to create a backend address pool via an ARM template for a load balancer with the following code:

```
            "type": "Microsoft.Network/loadBalancers/backendAddressPools",
        "apiVersion": "2020-05-01",
        "name": "[concat(variables('engineLbName'), '/LoadBalancerBEAddressPool')]",
        "dependsOn": [
            "[resourceId('Microsoft.Network/loadBalancers', variables('engineLbName'))]"
        ],
        "properties": {}

```

The loadbalancer it is targetting is using a basic SKU. When i attempt to deploy this arm template through the azure portal, I am given the following error message:

```
{
"error": {
    "code": "BackendOperationOnlyAllowedForStandardLB",
    "message": "Operation on backend pool /subscriptions/****/resourceGroups/*******/providers/Microsoft.Network/loadBalancers/LB-engine/backendAddressPools/LoadBalancerBEAddressPool not allowed. This operation is only allowed for standard SKU load balancers.",
    "details": []
}

```

}

Obviously, this indicates that i need to make my LB/LBIP of a standard SKU, however i specifically need this done on a basic SKU.

I am very confused as to why this error occurs, as we have many basic LB's that have backend configuration, and you are freely able to create a BE pool through the portal on a basic LB - I am unsure on how to do this via an ARM template.

# Answer
> 1 votes
I had the same issue, I downloaded the Template from Azure which effectively had my Load Balancer's Backend Address Pool as a "dependsOn" and as a "property".

This is under the load balancer's "dependsOn" list :

```
    "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', 'LB-db-phi-dbphipri', 'LoadBalancerBEAddressPool')]"

```

And the property under the Load Balancer's property list:

```
    "backendAddressPools": [
      {
        "name": "LoadBalancerBEAddressPool",
        "properties": {}
      }
    ]

```

Lastly, I had a child definition of the backendAddressPool as well

```
{
  "type": "Microsoft.Network/loadBalancers/backendAddressPools",
  "apiVersion": "2020-05-01",
  "name": "LB-db-phi-dbphipri/LoadBalancerBEAddressPool",
  "properties": {}
}

```

You don't need both. In my case I removed the "child" and the "dependsOn" and just have the property defined under the load balancer.

---
Tags: azure, load-balance
---


# Question
Title: What artifact managers are available in GCP?
I use Artifactory and Nexus3, but I wonder what artifact manager could be used in GCP? Is there a managed artifact manager or do I have to run one myself in a VM?

# Answer
> 3 votes
If the artifacts in question are docker images then the recommended artifact management solution is the Container Registry, well integrated with other GCP products producing and/or using such images.

AFAIK they don't have a real artifact manager for other kinds of artifacts, they suggest the rather general purpose Cloud Storage for that. You can find an example of such use in the Quickstart for Go guide. Most likely not what you're looking for:

```
artifacts:
  objects:
    location: 'gs://[BUCKET_NAME]/'
    paths: ['hello']

```

# Answer
> 2 votes
A new service have been released this year called Artifact Registry

---
Tags: artifactory, virtualization, gcp, nexus
---


title: Data processing infrastructure

text:
# Question
Title: Data processing infrastructure
We are building a system for data science in AWS and our flow is pretty simple.

1. Get the data - From redis
2. get the model - From FSx/EBS
3. run.

This process script should take something like 5-10 seconds depends on the size of the data and model. So far so good.

What we did so far is to build a python application (runs in kubernetes) that listen to a queue and runs the data science flow. The problem we faced was Pythons memory leak. what ever we did and every approach we took with python a long running application that loads/unloads large objects will grow and grow, So we are trying a new approach , running the script on its own process each time a new process is created and closed when finished (still in kubernetes).

My question is Is there a better way? AWS Lambda - could be a good solution but it has a memory/cpu limits that doesn't fit. Kubernetes Job - Inefficient when the script itself takes only a few seconds to run.

Are there any other solutions to run high load of requests with cpu/memory intensive work? (I'm looking for a resource/infrastructure solution, not a software one.)

# Answer
The service can be *always-on* listening on the queue for jobs, or *single-job* started by the queue only when new work arrives.

The tradeoff is *startup time* for single-jobs vs *cost* for always-on service.

Define the requirements - number of jobs per day, max latency, ram/cpu needed, etc and then select the right technology that can deliver it in the most cost effective way.

From AWS Lambda, AWS Step Functions, through K8S Jobs and AWS Fargate to AWS EC2 on spot pricing, and more. Plenty of options, depends on the requirements.

Hope that helps :)
> 1 votes

---
Tags: amazon-web-services, kubernetes, infrastructure
---


# Question
Title: Host credential manager and Docker runners
Imagine you have a GitLab Docker runner which you would like to pass credentials from a credential store. That is the CI/CD variable just designates the credentials profile name.

Is there a way to connect Docker containers to host's credential store?

# Answer
You need to provide more information about the technology stack.

In a nutshell, you would mix the responsibilities of the host, taking care for the gitlab runnner + credential store is not a good design practice. If the host goes down, you are loosing 2 essential services, instead of just one. Most likely you would have other consumers of the store. Also this is breaking the single responsibility principle.

I could tell you from own experience is that we use 'AWS Parameter store' for that ( H/A and detached service ). The secrets are consumed by a helm chart - https://github.com/cmattoon/aws-ssm and injected into the cluster as configurations. After that each interested party could use whatever it wants.
> 1 votes

---
Tags: docker, gitlab, security, credentials
---


# Question
Title: Gitlab CI - Deploy to an active docker container
I am running production code within an active docker container. I would like to use the Gitlab CI tool to auto deploy changes to the production environment WITHIN the docker container.

I am having trouble finding a clean way to do this.

One idea I have is to simply log into the docker container as part of the gitlab-ci automation script

* docker exec -it 82jf72h8dj2 bash
* then git pull from the appropriate directory

In theory, this will work... but what happens when the docker ID changes? Is there any way to detect this as part of the script? I would hate to have to keep updating the CICD variable since the docker ID seems to change fairly often...

# Answer
The image acts as a foundation for each container that you start from it.

You might do the update in your 'fashion' way, but containers are ephemeral - let's say it got restarted, you updates are lost and you are back to the previous version.

If you want to handle this process by yourself, how would you track your versions ? Essentially you would have a root docker image and after that it would be so hard to know which version is currently running ? Could you also safely roll-back version to version ? How about if somebody hijacks you container, due to some Unix Socket permissions with the Docker daemon ...

What I am trying to say, do not rediscover the wheel :)

Take advantage of modern technologies like Kubernetes, deploy each image for a new version there, you have a roll - out deployment, readiness probes and so on ... You would be safe that your software is always working, track the versions and have H/A.
> 1 votes

---
Tags: docker, gitlab, cicd, gitlab-ci-runner
---


# Question
Title: Can't change Windows Docker storage location (The parameter is incorrect)
I'm trying to move the Docker storage location to another drive. This is my configuration file:

```
{
  "registry-mirrors": [],
  "insecure-registries": [],
  "debug": false,
  "experimental": false,
  "data-root": "E:\\test"
}

```

I also tried to use `"graph"` instead of `data-root` (probably that was they to do it in the older versions) without any luck. I also gave read/write permissions to `Everyone` just in case. After restarting the daemon, I see the Docker directories and files are created in that folder, however when I try to pull the image, I'm getting following error:

> Executing task: docker build --pull --rm -f "Docker\BuildTools\Dockerfile" -t msbuildssdt "Docker\BuildTools" \< Sending build context to Docker daemon 5.632kB Error response from daemon: chtimes \\?\E:\test\tmp\docker-builder614293845\coverage: The parameter is incorrect. The terminal process "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command docker build --pull --rm -f "Docker\BuildTools\Dockerfile" -t msbuildssdt "Docker\BuildTools"" terminated with exit code: 1.

It's working well if I change the `data-root` value to any folder located on the `C:` drive.

# Answer
> 1 votes
The issue was that the `E:` drive was formatted with `exFAT` partition. After I formatted it to `NTFS` it started to work.

---
Tags: docker, windows
---


# Question
Title: How to deploy static website from public repo via Github Actions to private web server
I like to start an open-source project via Github where topics (markdown pages) can be created from the community. Via PR the changes get merged to the main repo and then it triggers a Github Action workflow. Inside this workflow, the markdown input gets processed to static HTML pages which should later get deployed to an Nginx web server.

The current (prototyped) deployment is done via SCP for GitHub Actions and SSH for GitHub Actions. For both actions, I have to provide the user and password inside the `workflow.yml` file.

To make the project public I need another approach, where others cannot get the credentials.

How can I realize my idea?

# Answer
> 1 votes
By coincidence, I have found a possible solution via Github Secrets.

---
Tags: deployment, continuous-deployment, github, secret-management
---


# Question
Title: How to run two react project through nginx on same machine
I am using the react for the frontend. I have a code which runs on port 3000.

Under that admin panel code is also there which I need to move to out of the project and run separately on different port let's say 3001. So on nginx config file I have created the location for both the project like this

```
Under server block
location /admin/ {
            proxy_pass http://127.0.0.1:3001;

        }

location / {
            proxy_pass http://127.0.0.1:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }

```

By this way when I open the localhost, my code is running properly.

Now if I type localhost/admin/ then it return 404.

For the nginx route confirmation, I have change the title of admin panel index.html so that it is clearly mentioned that whether my routes of nginx are working or not So after this when I hit the admin url then through inspect element I saw that title are changed but due to routes issue of main server it return 404.

I also wrote the alert hello world under index.html file of admin panel code so that it alert will generate when admin code is rendered.

After this when I Open the localhost/admin then alert will generate and then when I close the alert modal then page redirected to 404. I don't know why main code is overriding here.

What it seems like it pick the both the route at same time. So after hit the admin url instant index.html page is load and then routes load from 3000 port project instead of 3001. On 3000 port project there is no such route like this hence it return 404.

Anyone have any idea how to tackle this type of Issues.

Both project are running fine if run individually through the port number like localhost:3000/ or localhost:3001/admin/

Please suggest me that whether there is an issue from nginx side or from react side.

Any help or suggestion is really appreciated. Thanks in advance.

# Answer
Try to stop the react applications and see if the message changes - and tbh i think you should see 502 if nginx was not routing properly
> 1 votes

---
Tags: nginx
---


# Question
Title: RUN fails while installing Angular on Ubuntu Image
I am trying to create an image for my angular application for running unit and e2e tests. I started from the ubuntu image and then installed the other components. My dockerfile has the following statements.

```
FROM ubuntu:focal-20201008

RUN apt update && apt install -y \
    nginx \
    nodejs \
    npm \
    && npm install -g @angular/cli@9.1.12 \
    && rm -rf /var/lib/apt/lists/*

```

When I build the image using

```
sridhar@sridhar-HP-Laptop-15-H:~/abui/$ docker build --tag abui .

```

I get the following message (last few lines pasted here)

```
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
/usr/local/bin/ng -> /usr/local/lib/node_modules/@angular/cli/bin/ng

> @angular/cli@9.1.12 postinstall /usr/local/lib/node_modules/@angular/cli
> node ./bin/postinstall/script.js

The command '/bin/sh -c apt update && apt install -y     nginx     nodejs     npm     && npm install -g @angular/cli@9.1.12     && rm -rf /var/lib/apt/lists/*' returned a non-zero code: 1

```

P.S. I don't want to start from the node docker image as of now

# Answer
> 1 votes
Finally managed to generate the docker image for Angular. Here are is the screnshot.

I am listing the contents of the Docker File along with the comments that explain the reasoning and my learnings.

```
# Created by Sridhar Pandurangiah - 29 October 2020
# This Docker file helps create the containers for the Angular User Interface
#1 We would like to create from the node image and then add the layers. I had initially started from a base image and proceeded to add Ubuntu, it did not work out as creating a ubuntu from the base involves a lot of work and its rather baseless to start from a base image. Then switched to starting from the Ubuntu image and the problems I faced is documented in this question. So had to start from the node image. Also remember that docker containers have to address a single concern.

FROM node:15.1.0 as ab-suite-image

#Add Information about this image
LABEL maintainer="sridhar@st.in"
LABEL version="1.0"
LABEL decsription="This is a docker image built from the node image and includes angular9 and metronic theme"

#2 Add Angular and other peer dependencies that do not get installed by default to avoid the build from exiting with errors
RUN npm install -g @angular/cli@9.1.12 @angular/core @angular/common eslint chokidar jquery popper.js tslib --save

# Set environment variables for file locations if required

#3 Set the environment Variable to determine the environment where the application is deployed development | testing | staging | production
ENV AB_COMPLIANCE_ENV=development

#4 Set the working directory to copy the angular dependencies
WORKDIR /opt/ng

#5 We don't pull the code from GIT as it would mean storing the private ssh keys on a docker image that can be publicly accessed. This is is not advisable.
COPY package.json ./

#6 Update project dependencies using package.json. This stage is where we encountered a lot of issues with build failing as the shell scripts were returing errors. the flag --legacy-peer-deps ensures that the npm doesn't throw errors so the docker build continues
RUN npm install --legacy-peer-deps

#7 Copy all the other project files and build
COPY . ./
RUN ng build

#8 Configure Volumes if required

#9 Copy start Script if required
#COPY start.sh /start.sh
#CMD ["./start.sh"]

#10 Expose Port for the application
EXPOSE 4200 443

```

This docker image can be used to for running unit and E2E tests.

Some literature on the web ask you to install nginx but not advisable. Run nginx on a seperate dedicated container. On production you can build the angular application with the "prod" flag and copy the files so that nginx can serve them.

---
Tags: docker, node.js, npm
---


# Question
Title: Node-centric network metrics are very different from the sum of metrics of the Pods running on that node
### Context

I am trying to chart the network bandwidth usage of a node in 2 different manners:

1. By looking at global metrics for that node
2. By summing up the corresponding metric for each Pod

To achieve this, I am issuing the following Prometheus queries (*example for the receive bandwidth*):

* For the entire node (*metric from node-exporter*)

```
sum(irate(node_network_receive_bytes_total{instance="10.142.0.54:9100"}[$__rate_interval])) by (device)

```
* Per Pod (*metric from kubelet*)

```
sum(irate(container_network_receive_bytes_total{node="$node",container!=""}[$__rate_interval])) by (pod,interface)

```

The results are displayed in the following Grafana dashboard, after generating some load on a HTTP service called `thrpt-receiver`:

Here's what I see if I look at the raw metrics, without `sum()` and `irate()` applied:

### Problem

As you can see, results are vastly different, to the point I'm almost certain I am doing something wrong, but what?

What makes me especially suspicious about the Pod metrics is the supposedly increasing received bandwidth of kube-proxy (which AFAIK is not supposed to be receiving any traffic in iptables mode), and agents such as the Prometheus node-exporter, etc.

# Answer
> 1 votes
I found out what was happening in my graphs. All the Pods mentioned above have one thing in common: they use the host's network namespace, so their network metrics are *all identical*, and equal to the global *host's metric* (just with a slightly different precision).

```
$ kubectl - monitoring get pod -o jsonpath='{.spec.hostNetwork}' \
    prometheus-stack-prometheus-node-exporter-jnhw7

true

```

```
$ kubectl -n kube-system get pod -o jsonpath='{.items[*].spec.hostNetwork}' \
    kube-proxy-gke-triggermesh-product-control-plane-7fc0ad24-z586 \
    gke-metrics-agent-5cv4m \
    prometheus-to-sd-tk8jv \
    fluentbit-gke-xh879

true true true true

```

One way to see it is to compare the host's metric to *one* of the above Pods:

---
Tags: prometheus
---


# Question
Title: Trigger gitlab downstream pipeline from a upstream pipeline in a multi-project using trigger, rules and custom configuration variables
I have this scenario where I want to run the trigger in build stage only when `$FLAG` variable has been set by the `.pre` stage. However, the `build` stage never runs.

How should I conditionally trigger a downstream pipeline?

```
checkArtifactPresent:
  stage: .pre
  script:
    - >
      set +e;
      if curl -s -S -f $NEXUS_RAW_PICKER_REPOSITORY/${PRODUCT_FLAVOR}/${PRODUCT_FLAVOR}-${BUILD_TYPE}v${PICKER_TEMPLATE_TAG}.apk --output ${PRODUCT_FLAVOR}-${BUILD_TYPE}v${PICKER_TEMPLATE_TAG}.apk;
      then
        export FLAG= true;
      fi

buildArtifact:
  stage: build
  only:
   variables:
     - $FLAG
  trigger:
   project: dev/project_name
   strategy: depend

```

# Answer
> 1 votes
You could use dynamic child pipelines. (https://docs.gitlab.com/ee/ci/parent\_child\_pipelines.html#dynamic-child-pipelines).

You could create a job for triggering your job "buildArtifact" in a yml-file created with jsonnet in your "checkArtifactPresent". With using "--ext-str" or "--ext-code" in jsonnet. You can control the yml-file creation (https://jsonnet.org/learning/tutorial.html#parameterize-entire-config).

Read more https://jsonnet.org/

---
Tags: continuous-integration, gitlab, continuous-deployment, gitlab-ci-runner
---


# Question
Title: How do I edit my AWS ASG scheduled action useing the aws CLI
my scheduled action is called training my ASG is called temp\_4\_jenkins as I was planning to set up a pipeline on a Jenkins on my personal account to run the CLI commands.

```
aws application-autoscaling put-scheduled-action --service-namespace ec2 \
  --scalable-dimension ec2:instance:1 \
  --resource-id instance/t2.micro \
  --scheduled-action-name training \
  --schedule "cron(10 9 * * *)" \
  --scalable-target-action MinCapacity=0,MaxCapacity=0

```

I get back the error

An error occurred (ValidationException) when calling the PutScheduledAction operation: 1 validation error detected: Value 'ec2:instance:1' at 'scalableDimension' failed to satisfy constraint: Member must satisfy enum value set: \[cassandra:table:ReadCapacityUnits, dynamodb:table:ReadCapacityUnits, dynamodb:index:ReadCapacityUnits, rds:cluster:ReadReplicaCount, comprehend:document-classifier-endpoint:DesiredInferenceUnits, elasticmapreduce:instancefleet:SpotCapacity, lambda:function:ProvisionedConcurrency, comprehend:entity-recognizer-endpoint:DesiredInferenceUnits, appstream:fleet:DesiredCapacity, dynamodb:index:WriteCapacityUnits, elasticmapreduce:instancefleet:OnDemandCapacity, rds:cluster:Capacity, cassandra:table:WriteCapacityUnits, dynamodb:table:WriteCapacityUnits, elasticache:replication-group:Shards, custom-resource:ResourceType:Property, sagemaker:variant:DesiredInstanceCount, kafka:broker-storage:VolumeSize, ec2:spot-fleet-request:TargetCapacity, elasticache:replication-group:Replicas, elasticmapreduce:instancegroup:InstanceCount, ecs:service:DesiredCount\]

I found the command in the docs https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-scheduled-scaling.html

Then tried to modify it to ec2s instances?

I might be missing something obvious but why is the error talking about RDS and fleets I want to edit the schedule on my auto-scaling group to change the number of ec2s that get spun up?

# Answer
> 1 votes
I just solved it using put-scheduled-update-group-action

aws autoscaling put-scheduled-update-group-action --auto-scaling-group-name temp\_4\_jenkins --scheduled-action-name training --start-time 2020-11-23T09:10:00Z --min-size 0 --max-size 0 --desired-capacity 0 --region eu-west-1 --output json

---
Tags: aws-cli, asg
---


# Question
Title: What are the best practices for sharing production Postgres access with developers?
We're a small SaaS startup (~10 person team; mostly engineers).

We use Postgres on AWS and GCP in production.

We have signed contracts with some customers that prohibit us from giving full production access to developers (to avoid security concerns). I think this is a good thing.

However, every now and then our backend team needs access to the database to analyze data, table records, and see how things are working.

What are some recommended best practices for this?

At some larger companies, they have internal tooling that gives developers access to a middleman CLI through which they can run SQL queries. This middleman logs these for auditing purposes.

# Answer
We keep a RO clone of the important DB's. Any dev can access the basic RO clone if he's in the right dev group vpn, because the cloudsql instances are deployed in a private service net that peers with our private net and get be gotten to from the outside. If not they can get added it a group.. Then they just need the ip address and they need the user and password. There's an ROnly user given access to everything the postgres user gets, just RO.

PII data goes in a second PII DB, which is set up the same, but requires our compliance department to vet the person for pii access

We also have a firm policy of no poking the DB. Look at it, sure, clone if you have to to determine how to fix a data error, but no raw manhandling. It's to be done with a (possibly one shot) module off the codes db admin function.
> 1 votes

---
Tags: security, permissions, postgresql
---


# Question
Title: Can you inherit a template_cloudinit_config in another template_cloudinit_config object in Terraform?
I recently discovered `template_cloudinit_config` within Terraform, and I'm hoping I can utilize it to specify something like the code below. Basically my goal is to declare a core `template_cloudinit_config` that contains a number of shell scripts that should get run on every machine.

Then I'd like to declare a 2nd `template_cloudinit_config` that, without duplicating code, lets me essentially inherit the core set of scripts that should get applied to every instance AND define an additional script to run.

That way from a compute perspective, I could easily create specialized instances that have custom scripts applied to them, but still inherit a number of basic configurations. I know I could make this work with remote-exec provisioners, but I am trying to avoid them since Terraform says they should be used as a last resort.

```
data "template_cloudinit_config" "core_config" {
  part {
    content_type = "text/x-shellscript"
    content      = file("scripts/core_script1.sh")
  }

  part {
    content_type = "text/x-shellscript"
    content      = file("scripts/core_script2.sh")
  }
}

data "template_cloudinit_config" "custom_config" {
  part {
    content     = "${data.template_cloudinit_config.core_config.rendered}"
  }

  part {
    content_type = "text/x-shellscript"
    content      = file("scripts/custom_script.sh")
  }
}

resource "aws_instance" "vm1" {
  instance_type = "t2.small"
  ami           = data.aws_ami.ubuntu_ami.image_id

  # Other variables that declare subnet, key, etc

  user_data = "${data.template_cloudinit_config.core_config.rendered}"
}

resource "aws_instance" "vm2" {
  instance_type = "t2.small"
  ami           = data.aws_ami.ubuntu_ami.image_id

  # Other variables that declare subnet, key, etc

  user_data = "${data.template_cloudinit_config.custom_config.rendered}"
}

```

# Answer
The `cloudinit` provider only knows how to *encode* multipart MIME documents to pass to cloud init; there is no mechanism for *parsing* to modify and then re-encode.

However, a different way to frame your problem is of constructing a sequence of part objects in a local value and then passing them all together to the `cloudinit_config` data source, like this:

```
locals {
  core_config = tolist([
    {
      content_type = "text/x-shellscript"
      content      = file("${path.module}/scripts/core_script1.sh")
    },
    {
      content_type = "text/x-shellscript"
      content      = file("${path.module}/scripts/core_script2.sh")
    },
  ])
  custom_config = tolist([
    {
      content_type = "text/x-shellscript"
      content      = file("${path.module}/scripts/custom_script.sh")
    },
  ])
}

data "cloudinit_config" "core" {
  dynamic "part" {
    for_each = local.core_config
    content {
      content_type = part.value.content_type
      content      = part.value.content
    }
  }
}

data "cloudinit_config" "custom" {
  dynamic "part" {
    for_each = concat(
      local.core_config,
      local.custom_config,
    )
    content {
      content_type = part.value.content_type
      content      = part.value.content
    }
  }
}

resource "aws_instance" "vm1" {
  instance_type = "t2.small"
  ami           = data.aws_ami.ubuntu_ami.image_id

  # ...

  user_data = data.cloudinit_config.core.rendered
}

resource "aws_instance" "vm2" {
  instance_type = "t2.small"
  ami           = data.aws_ami.ubuntu_ami.image_id

  # ...

  user_data = data.cloudinit_config.custom.rendered
}

```

The above is using `dynamic` blocks to generate a dynamic number of `part` blocks based on the number of elements in a list, which means you can focus on making sure the lists have the necessary items, using whatever dynamic expressions you need to decide that, and have Terraform project that into zero or more `part` blocks automatically.

**Note:** the `hashicorp/template` provider has been deprecated and continues to be available only for backward-compatibility. For that reason, I wrote the above to use the `hashicorp/cloudinit` provider instead. Its `cloudinit_config` data source is based on what was formerly `template_cloudinit_config`.
> 2 votes

---
Tags: terraform, amazon-ec2
---


title: Pull request and merge actions in CI/CD

text:
# Question
Title: Pull request and merge actions in CI/CD
The CI/CD pipeline supports pipelines per branch but no pipeline for feature branches is triggered automatically. There are pipelines deployed for the following branches: `development`, `master`. The respective pipeline is triggered `onCommit` event `(codeCommitRepo.onCommit('OnCommit', {})` so whenever there is any code push to the branch. We are planning to use git-flow as the branching strategy but don't exactly see the advantages of having another branch called `staging`, in addition to `development`, `master`.

1. Is there a use of having a third branch like "staging" when using CI/CD?

The CI/CD pipeline looks as follows:

2. At what stage should the PR from the feature branch be created?
3. At what stage should the PR be merged into the development branch?
4. At what stage should the PR from the development branch to master be created?
5. At what stage should the PR be merged into the master branch?
6. What if the development pipeline fails? Should the code be manually unmerged to get development back in the stable condition?
7. What if the master pipeline fails? Is the code being merged in the branch after the pipeline succeeds?

I would like to understand what the flow should look like starting from a feature branch. (P.S: Not interested in Trunk based development strategy)

Also, the pipeline is coming from https://github.com/awslabs/aws-simple-cicd and is written using AWS-CDK

# Answer
1. In my opinion there should be a staging branch , which holds the production candidate code.And instead of a Test env , have a staging env which will be complete replica of Prod env. In the Staging env the QA can perform their testing and other checks.

* Dev env = only for developer.
* Stage env = Replica of Prod and holds production candidate build/code , where QA can perform their testing and simulate Prod.

Having a Staging branch has its benefit as you can have code which will merge to master and deploy to prod , and the developer can experiment/work on develop branch without worrying of any accidental merge to master directly.

2. Once someone completes a feature or fixes a bug/error or implementation is done and testing needs to be performed.
3. same as above.
4. Once the code has been passes the test's and QA verified on staging env and No new feature are to be added to Prod , it can be merged to master.
5. No new feature are to be added to Prod , QA passed and test cases passed, it can be merged to master
6. That's where the Staging branch will help , as even if code fails on stage as it is supposed to be complete replica of prod env. we can revert or commit the fix again without worrying of our master branch.
> 1 votes

---
Tags: amazon-web-services, continuous-integration, continuous-deployment, continuous-delivery, aws-codepipeline
---


# Question
Title: AWS elb vs google cloud for multiple small nodejs mini-apps deployment
Currently i use AWS ELB `--single` instances do deploy & manage multiple versions of the same `nodejs` app (over 10), which differ only by the configuration. Each app is running some endless process 24/7. I want to be able to manage (start/stop/update) them separately and efficiently. Currently it's very easy to do so with `elb deploy` command.

However, the costs went seriously up lately (while the load increased just by 10-20%). About half of the cost is the data transfer and 40% is the EC2 instances themselves (`t2.nano`).

Would the use of Google Cloud be more cost efficient? and more importantly, is there a similar way do deploy and manage 10x instances of the same app? Sure when i finish reading all the docs, i might have an idea, but hoping to get some advise about the direction of research or probably about the solution itself.

# Answer
> 1 votes
you can try google cloud run. here you can run containerized applications on a fully managed serverless platform. You might have to containerize your application. But it can help you reduce the cost as the min container can be 0 (zero) and if any to your app is there cloud run can automatically scale to meet the demand.

---
Tags: amazon-ec2, google-cloud-platform, aws-elb
---


# Question
Title: backup dockerise mysql database from host volume
I use a VPS (my host) where a *LAMP server* was installed. I already have a database associated to host *mariaDB server Ver 15.1 Distrib 10.1.47* and *automysqlbackup* backups it. This part works well.

For a "new project", we use now docker servers and one with a *mysql 5.7* and a volume to save this new project database in a host folder, for exemple: */path/on/host/dockerise/db/*

I want to backup too this new database.

What is the right way?

1. Is there a way with automysqlbackup? I think no because it uses host mariaDb server and *mysqldump*, and you shouldn't have two servers working on the same database (https://dev.mysql.com/doc/refman/5.7/en/multiple-data-directories.html)
2. Directly with *mysqldump* ?
3. Or just create a bash script and CRON it?

# Answer
based on @ulrich answer, but with **mysqldump** :

```
DATE_TIME=`date +"%Y%m%d_%H%M"
CONTAINER_NAME="mysql_server"
CONTAINER=`docker ps -q -f name=${CONTAINER_NAME}`
PASSWORD=`docker exec ${CONTAINER} sh -c 'echo $MYSQL_ROOT_PASSWORD'`
BACKUP_FILE=${DATE_TIME}_${CONTAINER_NAME}.backup.sql.gz
CONTAINER_BACKUP_DIR="/var/lib/mysql/"
HOST_DATA_DIR="/path/on/my/VM/correspond/to/docker/volume/"
HOST_BACKUP_DIR="/other/path/on/VM/"
## run backup in container
docker exec ${CONTAINER} sh -c "/usr/bin/mysqldump -h localhost -u root -p${PASSWORD} --all-databases | gzip -9 -c > ${CONTAINER_BACKUP_DIR}${BACKUP_FILE}"
## move to final folder
mv ${HOST_DATA_DIR}${BACKUP_FILE} ${HOST_BACKUP_DIR}

```

HOST\_DATA\_DIR and HOST\_BACKUP\_DIR are differents because I have an other daemon to save backup to a data center, and because in HOST\_DATA\_DIR, root can only read and execute (r\_x).
For all folder paths, be careful to have a final '/', otherwise you should be surprised!

and if you run it automatically with a CRON job, it should be helpfull to manage rotate to delete old backup:

```
## rotate save management to keep only last MAX_BACKUP files
MAX_BACKUP=3
${HOST_DATA_DIR}rotate-databases-backup.log
echo ${HOST_BACKUP_DIR}${BACKUP_FILE} >> ${HOST_DATA_DIR}rotate-databases-backup.log
BACKUPED_NB=$(ls ${HOST_BACKUP_DIR}*${CONTAINER_NAME}.backup.sql.gz | wc --lines)
TOTAL=$(wc --lines < ${HOST_DATA_DIR}rotate-databases-backup.log)
FILES_NB_TO_DELETE=$(expr $TOTAL - $MAX_BACKUP)
if [[ $FILES_NB_TO_DELETE -gt 0 ]]; then
    head --lines=$FILES_NB_TO_DELETE ${HOST_DATA_DIR}rotate-databases-backup.log | xargs rm
    ls ${HOST_BACKUP_DIR}*${CONTAINER_NAME}.backup.sql.gz > ${HOST_DATA_DIR}rotate-databases-backup.log
fi

```
> 1 votes

# Answer
I have a little script for my MariaDb database inside a docker container. The setup is comparable. I have a database container with a mounted volume. Furthermore I have a second volume for backups mounted under `/backup`.

The script is run on the host via cron and uses the database instance inside the container, so only one database accesses the data. That is the docker exec part. I'm sure, you can adopt it to mysql. You only have to configure the CONTAINER\_NAME and change the command inside the container.

```
#!/bin/bash
DATE_TIME=`date +"%Y_%m_%d_%H_%M"`
CONTAINER_NAME="mariadb"
CONTAINER=`docker ps -q -f name=${CONTAINER_NAME}`
PASSWORD=`docker exec ${CONTAINER} sh -c 'echo $MYSQL_ROOT_PASSWORD'`
BACKUPFILE=${DATE_TIME}_${CONTAINER_NAME}.backup.gz

echo "Backup of MariaDb"
echo ""
echo "Old backps will be deleted."
echo "Datenbank Container Name: $CONTAINER_NAME"
echo "Datenbank Container:  $CONTAINER"

echo "Writing backup to ${BACKUPFILE}"
echo ""
docker exec ${CONTAINER} sh -c "find /backup/ -mindepth 1 -mtime +8 -delete; /usr/bin/mariabackup --backup --user root --password=${PASSWORD} --stream=xbstream | gzip > /backup/${BACKUPFILE}"
echo ""
echo "Backup finished"

```
> 1 votes

---
Tags: docker, mysql, volume
---


title: How to remove the AWS Backups

text:
# Question
Title: How to remove the AWS Backups
I'm using AWS Backup to create snapshots of my production server. My current backup plan has infinite retention and that ran me into gigabytes of storage.

What would be the best way to fix that? I saw I can't remove the backups in bulk (can only select and remove each single backup, but I have 100s).

Is it possible to modify the backup rule so that it removes the previous backups? Or is there a way to select and remove all the backups done by AWS Backup?

# Answer
Coincidentally I had to do something very similar yesterday. This is the script I used:

```
#!/bin/bash -e

VAULT_NAME=...   # put your Backup Vault name here

for ARN in $(aws backup list-recovery-points-by-backup-vault --backup-vault-name "${VAULT_NAME}" --query 'RecoveryPoints[].RecoveryPointArn' --output text); do
  echo "deleting ${ARN} ..."
  aws backup delete-recovery-point --backup-vault-name "${VAULT_NAME}" --recovery-point-arn "${ARN}"
done

```

You can also add `--by-created-before` to delete the old backups only.

Hope that helps :)
> 2 votes

---
Tags: amazon-web-services, backup
---


# Question
Title: How to ensure that the docker build fails if an ENV has not been set?
This github discussion was found. It seems that it is allowed to build a docker image while a certain ENV does not have been set.

How to ensure that the docker build fails if an ENV has not been set?

# Answer
An empty of non existent environment variable is the same thing, there's no reason Docker do not allow you to pass an empty variable as it could be a valid use case.

It's up to your responsibility to ensure needed environment variables are there and give an error message back when not.

Something like this:

```
RUN if [ -z "$AN_ENV_VAR" ]; then echo 'Environment variable AN_ENV_VAR must be specified. Exiting.'; exit 1; fi

```

You can play with the exit code to automate some actions on failure around your `docker build` command.
> 8 votes

# Answer
To error out the build, just add the following with your env variable in the docker-compose file.

```
${ENV_VAR?Variable ENV_VAR not set}

```

example:

```
image: consul:${TAG?Variable TAG not set}

```
> 4 votes

# Answer
If the `if` command construct is very complex for you, you can always simply it like

```
RUN [ -n "$VAR" ]

```

This asserts the variable value length is nonzero. If it's empty or not set it'll exit with 1. This is also same as running `RUN test -n "$VAR"`

I see this error message on my machine

```
The command '/bin/sh -c [ -n "$VAR" ]' returned a non-zero code: 1

```
> 1 votes

---
Tags: docker
---


title: Ansible multiple commands to a file

text:
# Question
Title: Ansible multiple commands to a file
You can see bellow how it looks like my Ansible Script.

My question is what i need to change to get output from multiple commands to a file.The problem is that i get output only from the first command.

I have 200 vrf,do i really need to make multiple tasks fior multiple commands,or there is another solution for it.

I would highly appreciate any response.

```
---
- name: PING_TenGig_Ethernet_VRFs
  hosts: fr1.s05
  gather_facts: false
  connection: local

  tasks:
    - name: run multiple commands on remote nodes
      ios_command:
        commands:
          - show bgp vrf Mgmt-intf
          - show bgp vrf cha-00 all summary
          - show bgp vrf cha-001 all summary
          - show bgp vrf cha-002 all summary
          - show bgp vrf cha-00303 all summary

      register: print_output

    -  debug: var=print_output.stdout_lines

    - name: save output to a file
      copy: content="{{ print_output.stdout[0] }}" dest="./output/{{ inventory_hostname }}.txt"

```

# Answer
> 1 votes
Judging by the documentation, the result of your `run multiple commands on remote nodes` block is an array. You're writing only the first item of that array with `{{ print_output.stdout[0] }}`. The `[0]` here is the pointer to the first element of the array. Try removing it and see if the result fits your needs.

**UPD**: Use this to write several strings into a file:

```
- name: save output to a file
  lineinfile:
    create: yes
    line: "{{item}}"
    path: ./output/{{ inventory_hostname }}.txt
  with_items: "{{ print_output.stdout }}"

```

---
Tags: ansible
---


# Question
Title: Docker in docker volume mount doesn't work
I have the below command in my `Jenkinsfile`:

```
docker run --rm -v "${WORKSPACE}":/var/cache/de --entrypoint=/usr/local/bin/pytest ${IMAGE_NAME}:${IMAGE_VERSION} -m "not require_dss" -s -v --cov-report term --cov=app_dss_bundle --junitxml=/var/cache/de/rtest.xml tests

ls -l

```

I'm running inside docker slave, so it means its docker inside docker. I can't see the `rtest.xml` in the `WORKSPACE` afterward (it works for me in my private linux docker env). I already tried to run the suggestion of `-v /var/run/docker.sock:/var/run/docker.sock` but it didn't help. any other idea?

# Answer
Single quotes in shell meant to leave the enclosed string 'as is'. That is the variable inside single quotes isn't going to be evaluated. Try changing `'${WORKSPACE}'` for `"${WORKSPACE}"`.
> 2 votes

---
Tags: docker, jenkinsfile, volume
---


# Question
Title: Kubernetes configuration with yaml anchors
I have a `deployment.yaml` file and want to reuse the environment for all my deployments like this:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: beat
spec:
  selector:
    matchLabels:
      app: beat
  template:
    metadata:
      labels:
        app: beat
    spec:
      containers:
      - name: beat
        image: myimage
        command: ["celery", "-A", "wsgi.celery", "beat"]
        env: &default
        - name: FIRST_ENV
          value: my-value
        - name: SECOND_ENV
          value: another-value
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: flower
spec:
  selector:
    matchLabels:
      app: flower
  template:
    metadata:
      labels:
        app: flower
    spec:
      containers:
      - name: flower
        image: myimage
        command: ["celery", "flower", "-A", "wsgi.celery"]
        env: *defaultenv

```

But it seems like `kubectl apply -f deployment.yaml` won't work with YAML anchors.

```
error: error parsing deployment.yaml: error converting YAML to JSON: yaml: unknown anchor 'defaultenv' referenced

```

Is it possible to use YAML anchors or is there another preferred approach of how to reuse repeating blocks for k8s configuration?

# Answer
YAML anchors are supported, but only for the same YAML file. You can't create the anchor (`&`) on a deployment file and reference (`*`) the value on another one.

If you want to share ENVs values across multiple Deployments, you can create a ConfigMap with the ENVs and use the `envFrom` spec. Example:

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-configmap
data:
  FIRST_ENV: my-value
  SECOND_ENV: another-value
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: beat
spec:
  selector:
    matchLabels:
      app: beat
  template:
    metadata:
      labels:
        app: beat
    spec:
      containers:
      - name: beat
        image: myimage
        command: ["celery", "-A", "wsgi.celery", "beat"]
        envFrom:
        - configMapRef:
            name: my-configmap
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: flower
spec:
  selector:
    matchLabels:
      app: flower
  template:
    metadata:
      labels:
        app: flower
    spec:
      containers:
      - name: flower
        image: myimage
        command: ["celery", "flower", "-A", "wsgi.celery"]
        envFrom:
        - configMapRef:
            name: my-configmap

```
> 8 votes

# Answer
The preferred way is to use helm and create a chart. Helm practically generates your manifests based on templates.
> 0 votes

---
Tags: kubernetes, deployment, yaml, kubectl
---


# Question
Title: Terraform fails on creating network with libvirt provider
I wanted to spin up a test environment locally using the description from this stackoverflow answer: https://stackoverflow.com/a/58607900/4397899

The main.tf looks like

```
################################################################################
# ENV VARS
################################################################################

# https://www.terraform.io/docs/commands/environment-variables.html

variable "VM_COUNT" {
  default = 3
  type = number
}

variable "VM_USER" {
  default = "developer"
  type = string
}

variable "VM_HOSTNAME" {
  default = "ci-vm"
  type = string
}

variable "VM_IMG_URL" {
  default = "https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img"
  type = string
}

variable "VM_IMG_FORMAT" {
  default = "qcow2"
  type = string
}

variable "VM_CIDR_RANGE" {
  default = "10.10.10.10/24"
  type = string
}

################################################################################
# PROVIDERS
################################################################################

# instance the provider
provider "libvirt" {
  uri = "qemu:///system"
}

################################################################################
# DATA TEMPLATES
################################################################################

# https://www.terraform.io/docs/providers/template/d/file.html

# https://www.terraform.io/docs/providers/template/d/cloudinit_config.html
data "template_file" "user_data" {
  template = file("${path.module}/cloud_init.cfg")
  vars = {
    VM_USER = var.VM_USER
  }
}

data "template_file" "network_config" {
  template = file("${path.module}/network_config.cfg")
}

################################################################################
# RESOURCES
################################################################################

resource "libvirt_pool" "vm" {
  name = "${var.VM_HOSTNAME}_pool"
  type = "dir"
  path = "/tmp/terraform-provider-libvirt-pool-ubuntu"
}

# We fetch the latest ubuntu release image from their mirrors
resource "libvirt_volume" "vm" {
  count  = var.VM_COUNT
  name   = "${var.VM_HOSTNAME}-${count.index}_volume.${var.VM_IMG_FORMAT}"
  pool   = libvirt_pool.vm.name
  source = var.VM_IMG_URL
  format = var.VM_IMG_FORMAT
}

# Create a public network for the VMs
resource "libvirt_network" "vm_public_network" {
   name = "${var.VM_HOSTNAME}_network"
   mode = "nat"
   domain = "${var.VM_HOSTNAME}.local"
   addresses = ["${var.VM_CIDR_RANGE}"]
   dhcp {
    enabled = true
   }
   dns {
    enabled = true
   }
}

# for more info about paramater check this out
# https://github.com/dmacvicar/terraform-provider-libvirt/blob/master/website/docs/r/cloudinit.html.markdown
# Use CloudInit to add our ssh-key to the instance
# you can add also meta_data field
resource "libvirt_cloudinit_disk" "cloudinit" {
  name           = "${var.VM_HOSTNAME}_cloudinit.iso"
  user_data      = data.template_file.user_data.rendered
  network_config = data.template_file.network_config.rendered
  pool           = libvirt_pool.vm.name
}

# Create the machine
resource "libvirt_domain" "vm" {
  count  = var.VM_COUNT
  name   = "${var.VM_HOSTNAME}-${count.index}"
  memory = "1024"
  vcpu   = 1

  cloudinit = "${libvirt_cloudinit_disk.cloudinit.id}"

  # TODO: Automate the creation of public network
  network_interface {
    network_id = "${libvirt_network.vm_public_network.id}"
    #network_id = "6d8e2494-835d-4baf-a14f-3a5c705febcc"
    #network_name = "vm_docker_network"
    network_name = "${libvirt_network.vm_public_network.name}"
  }

  # IMPORTANT
  # Ubuntu can hang is a isa-serial is not present at boot time.
  # If you find your CPU 100% and never is available this is why.
  #
  # This is a known bug on cloud images, since they expect a console
  # we need to pass it:
  # https://bugs.launchpad.net/cloud-images/+bug/1573095
  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }

  console {
    type        = "pty"
    target_type = "virtio"
    target_port = "1"
  }

  disk {
    volume_id = "${libvirt_volume.vm[count.index].id}"
  }

  graphics {
    type        = "spice"
    listen_type = "address"
    autoport    = true
  }
}

################################################################################
# TERRAFORM CONFIG
################################################################################

terraform {
  required_version = ">= 0.12"
}

```

The network\_config.cfg looks like this

```
version: 2
ethernets:
  ens3:
     dhcp4: true

```

Steps to Reproduce Issue

Run

```
terraform init
terraform apply

```

Then I get the error message:

```
Error: Error creating libvirt network: virError(Code=38, Domain=0, Message='error creating bridge interface ci-vm_network-br: Numerical result out of range')

```

# Answer
I guess the issue is here:

default = "10.10.10.10/24"

you have defined a network address and not a subnet. Try and change the IP address to a subnet address it should work.
> 1 votes

---
Tags: terraform
---


# Question
Title: Deploy Docker Compose from different repositories
I have 3 separate repositories, which contains API, web app, and Admin projects. All 3 runs on a Digital Ocean docker machine, and I deploy the 3 using docker-compose (I want to keep things simple).

Every time a push to master with a tag happen, GithubActions build each separate project and publish a docker image (with the corresponding tag), and then I manually launch `docker compose up -d`. The docker compose file point to the latest version of each image, so it get automatically reloaded and launched.

Is there a better way to automatically reload the docker compose from GitHub Actions? I ideally want that each time a repository build an image and push it to the registry, the docker compose automatically reload.

# Answer
You can utilize watchtower to restart the specified containers each time new image of that container is avaialble.

> Watchtower : with watchtower you can update the running version of your containerized app simply by pushing a new image to the Docker Hub or your own image registry. Watchtower will pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially. Run the watchtower container with the following command:
>
> ```
> $ docker run -d \
>     --name watchtower \
>     -v /var/run/docker.sock:/var/run/docker.sock \
>     containrrr/watchtower
>
> ```

docker-compose integration example:

```
services:
  watchtower:
    command: --label-enable --cleanup --interval 300
    image: containrrr/watchtower
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
    network_mode: none
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  mariadb:
      depends_on:
        - watchtower
      env_file: .mariadb.env
      image: mariadb:10
      labels:
        - "com.centurylinklabs.watchtower.enable=true"
      networks:
        - default
      ports:
        - 3306:3306
      restart: always
      volumes:
        - ./data/volumes/mariadb:/var/lib/mysql

```

To check the logs of the updation you can execute `docker-compose logs watchtower`

docker-compose integration reference: https://chriswiegman.com/2019/12/keeping-docker-containers-updated/
> 1 votes

---
Tags: docker, docker-compose, github
---


# Question
Title: How to make Terraform Modules wait for resources to be created in place of using computed values
Today I am working on building out several custom Terraform Modules. The issue that I am trying to figure out how to work around dependencies within modules. Until TF 0.12 is released we cannot declare a module to be dependent upon another module. So, in this root level main.tf:

```
# ROOT level main.tf
# -------------------------------------------------------------------
# Create NAT Gateway - Associates EIP as well
# -------------------------------------------------------------------
module "vpc_nat_gateway" {
  source            = "./vpc_nat_gateway"
  vpc_id            = "${ module.vpc.id }"
  public_subnet_ids = "${ module.vpc_subnets.public_subnet_ids }"
  private_cidr      = "${ var.private_cidr }"
  common_tags       = "${ local.common_tags }"
}

# -------------------------------------------------------------------
# Create Private Routes
# -------------------------------------------------------------------
module "vpc_private_route" {
  source         = "./vpc_private_route"
  vpc_id.        = "${ module.vpc.id }"
  nat_gateway_id = "${ module.vpc_nat_gateway.nat_gateway_id }"
  common_tags    = "${ local.common_tags }"
}

# vpc_private_route module - main.tf
data "aws_nat_gateway" "az1" {
  vpc_id = "${ var.vpc_id }"

  tags {
    Name = "*NAT GW AZ 1"
  }
}

data "aws_nat_gateway" "az2" {
  vpc_id = "${ var.vpc_id }"

  tags {
    Name = "*NAT GW AZ 2"
  }
}

```

The result output is:

```
------ SNIP -----
module.vpc_nat_gateway.aws_nat_gateway.nat[1]: Creation complete after 1m50s (ID: nat-02a7f4279cec3a6c8)
module.vpc_nat_gateway.aws_nat_gateway.nat.0: Still creating... (2m0s elapsed)
module.vpc_nat_gateway.aws_nat_gateway.nat[0]: Creation complete after 2m0s (ID: nat-0695a12d9c0305e4c)

    Error: Error applying plan:

    3 error(s) occurred:

    * module.vpc_private_route.data.aws_subnet_ids.private: data.aws_subnet_ids.private: no matching subnet found for vpc with id vpc-0b530d1885e74067b
    * module.vpc_private_route.data.aws_nat_gateway.az2: data.aws_nat_gateway.az2: no matching NAT gateway found: {
    Filter: [{
        Name: "vpc-id",
        Values: ["vpc-0b530d1885e74067b"]
        },{
        Name: "tag:Name",
        Values: ["*NAT GW AZ 2"]
        }]
    }
    * module.vpc_private_route.data.aws_nat_gateway.az1: data.aws_nat_gateway.az1: no matching NAT gateway found: {
    Filter: [{
        Name: "vpc-id",
        Values: ["vpc-0b530d1885e74067b"]
        },{
        Name: "tag:Name",
        Values: ["*NAT GW AZ 1"]
        }]
    }

```

As observed in the output the Nat Gateways are created. `Terraform show` output tells us the Filters are correct:

```
    module.vpc_nat_gateway.aws_nat_gateway.nat.0:
        id = nat-0695a12d9c0305e4c
        allocation_id = eipalloc-023ca087ad4fb830e
        network_interface_id = eni-015e39fc8d3bc0de3
        private_ip = 172.16.254.16
        public_ip = 18.215.5.116
        subnet_id = subnet-0f2c039e8fd804f30
        tags.% = 7
        tags.Environment = development
        tags.Infrastructure = No
        tags.Name = **redacted** NAT GW AZ 1
    module.vpc_nat_gateway.aws_nat_gateway.nat.1:
        id = nat-02a7f4279cec3a6c8
        allocation_id = eipalloc-0a95264c2eef26673
        network_interface_id = eni-03bddcca2fbeeff44
        private_ip = 172.16.254.84
        public_ip = 3.91.167.246
        subnet_id = subnet-08ee61f3aa43acbe9
        tags.% = 7
        tags.Environment = development
        tags.Infrastructure = No
        tags.Name = **redacted** NAT GW AZ 2

```

Executing a subsequent `terraform apply` runs without any errors.

```
# Yes, the IDs are different in this example than from above.
# ---- SNIP ----
    module.vpc_private_route.data.aws_nat_gateway.az1:
        id = nat-0c127e538a26b2bd5
        allocation_id = eipalloc-01775b8e88502d4b9
        network_interface_id = eni-0b0bd2203bd3f5873
        private_ip = 172.16.254.45
        public_ip = 3.83.199.207
        state = available
        subnet_id = subnet-050f6fc499a455a97
        tags.% = 7
        tags.Environment = development
        tags.Infrastructure = No
        tags.Name = **redacted** NAT GW AZ 1
        vpc_id = vpc-057a1208002394e1b
    module.vpc_private_route.data.aws_nat_gateway.az2:
        id = nat-0325fe2ba1184815b
        allocation_id = eipalloc-0df309e8b533b35b6
        network_interface_id = eni-00e850031318b2a41
        private_ip = 172.16.254.92
        public_ip = 3.88.44.14
        state = available
        subnet_id = subnet-0191ae48f099aa808
        tags.% = 7
        tags.Infrastructure = No
        tags.Name = **redacted** NAT GW AZ 2
        vpc_id = vpc-057a1208002394e1b
    module.vpc_private_route.data.aws_subnet_ids.private:
        id = vpc-057a1208002394e1b
        ids.# = 2
        ids.1528047303 = subnet-03a4f5228ae9f1714
        ids.1908543416 = subnet-0d915cc4899877eb9
        tags.% = 1
        tags.Name = *Private*
        vpc_id = vpc-057a1208002394e1b

```

**What should I be doing different** to cause this TF Module to wait for the resources to be created before polling for the resource? In Ansible I could just issue a wait command or run a loop searching for criteria before proceeding.

Thank you for your thoughts!

**PLEASE NOTE** all of the "ids" shown in this output will be dead before you read this post. All data has been sanitized based on environmental security policies.

# Answer
> 7 votes
**Update: As of TF 0.13x, `depends_on` is supported to create dependencies between modules. Using `depends_on` should be preferable over using the method detailed below.**

The previous most popular answer is out of date with Terraform 0.12.24.

`depends_on` is a protected variable, and cannot be used in a `module`. In addition there are a few syntax differences.

I've updated the example below.

```
# ROOT level main.tf
# -------------------------------------------------------------------
# Create NAT Gateway - Associates EIP as well
# -------------------------------------------------------------------
module "vpc_nat_gateway" {
  source            = "./vpc_nat_gateway"
  vpc_id            = module.vpc.id
  public_subnet_ids = module.vpc_subnets.public_subnet_ids
  private_cidr      = var.private_cidr
  common_tags       = local.common_tags
}

# -------------------------------------------------------------------
# Create Private Routes
# -------------------------------------------------------------------
module "vpc_private_route" {
  source         = "./vpc_private_route"
  vpc_id.        = module.vpc.id
  nat_gateway_id = module.vpc_nat_gateway.nat_gateway_id
  common_tags    = local.common_tags

  # Depends is a custom variable, depends_on is a reserved keyword.
  depends = [module.vpc_nat_gateway.nat_gateway_id]
}

```

```
# vpc_private_route module - main.tf
variable "depends" {
  default = []
}

resource "null_resource" "depends_on" {
  triggers = {
    depends_on = "${join("", var.depends)}"
  }
}

data "aws_nat_gateway" "az1" {
  vpc_id = var.vpc_id

  depends_on = [
    null_resource.depends_on
  ]
}

data "aws_nat_gateway" "az2" {
  vpc_id = var.vpc_id

  depends_on = [
    null_resource.depends_on
  ]
}

```

# Answer
> 5 votes
These are hacks (understandably as you couldn't explicitly do this in Terraform \< 0.13).

Now however, with 0.13, we have `depends_on` for modules: https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md#0130-august-10-2020

# Answer
> 4 votes
There is a hacky workaround for getting Terraform to do module dependencies. You can force the module to be aware of the Terraform calling it like this:

```
# ROOT level main.tf
# -------------------------------------------------------------------
# Create NAT Gateway - Associates EIP as well
# -------------------------------------------------------------------
module "vpc_nat_gateway" {
  source            = "./vpc_nat_gateway"
  vpc_id            = "${ module.vpc.id }"
  public_subnet_ids = "${ module.vpc_subnets.public_subnet_ids }"
  private_cidr      = "${ var.private_cidr }"
  common_tags       = "${ local.common_tags }"
}

# -------------------------------------------------------------------
# Create Private Routes
# -------------------------------------------------------------------
module "vpc_private_route" {
  source         = "./vpc_private_route"
  vpc_id.        = "${ module.vpc.id }"
  nat_gateway_id = "${ module.vpc_nat_gateway.nat_gateway_id }"
  common_tags    = "${ local.common_tags }"

  depends_on = ["${module.vpc_nat_gateway.nat_gateway_id}"]
}

```

```
# vpc_private_route module - main.tf
variable "depends_on" {
  default = []
}

resource "null_resource" "depends_on" {
  triggers {
    depends_on = "${join("", var.depends_on)}"
  }
}

data "aws_nat_gateway" "az1" {
  vpc_id = "${ var.vpc_id }"

  tags {
    Name = "*NAT GW AZ 1"
  }

  depends_on = [
    "null_resource.depends_on"
  ]
}

data "aws_nat_gateway" "az2" {
  vpc_id = "${ var.vpc_id }"

  tags {
    Name = "*NAT GW AZ 2"
  }

  depends_on = [
    "null_resource.depends_on"
  ]
}

```

It adds a lot of boilerplate but you will get the desired effect.

---
Tags: terraform, terraform-module
---


# Question
Title: How can I check if there is a new build the same jenkins pipeline
I have a github multibranch pipeline, in declarative format. It is configured to trigger on pushes to pull request branches (ie, branches which are included in pull requests to a target branch, say `main`.

If a new commit comes in before the execution of a previous commit is finished, this will trigger a concurrent build of the pipeline. I want to maintain this behaviour, but **need to know if there is a new pipeline running** in one of the stages.

Ie I want a groovy script step like this pseudo code:

```
if (build_number + 1) is_currently_running
  do one thing
else
  do something else

```

Is there any way to ask Jenkins if build n+1 is running?

# Answer
> 1 votes
This should be fairly straightforward to do in a script block. I don't think there's a declarative-native way to do this.

I use this script block to cancel builds for earlier (i.e. outdated) revisions of PRs:

```
script {
  // currentBuild is a Pipeline-builtin variable for accessing the Build object
  // https://www.jenkins.io/doc/book/pipeline/getting-started/#global-variable-reference
  def build = currentBuild

  while(true) {
    build = build.getPreviousBuild()

    // exit the loop if we have finished iterating over builds
    // (groovy doesn't have a do...while feature)
    if (build == null) break

    def rawBuild = build.rawBuild

    if (rawBuild.isBuilding()) {
      // abort the build
      rawBuild.doTerm()
    }
  }
}

```

As you can hopefully see, this iterates over **all** previous builds and uses the `isBuilding()` method to find ones that are currently running.

If you want to check later builds instead of previous ones, you can use `getNextBuild()` instead (I believe the API doc is here, it's been a while since I wrote this so this might be the wrong class).

And if you want to check only one directly adjacent build instead of all earlier/later builds, you can just omit the loop and only call `getPreviousBuild()`/`getNextBuild()` once.

---
Tags: jenkins, jenkins-pipeline, jenkinsfile
---


# Question
Title: Cannot access service using docker-swarm, but without
Currently I try to setup docker-swarm using two nodes and deploy portainer on them.

Both nodes are virtual machines on the same host and are on the same network (172.16.255.255). Addtionally there is a firewall in these local network providing a VPN server (255.255.0.0). The VPN routes requests to 172.16.255.255 in the local network (e. g. 10.0.0.3 can access 172.16.0.80). No ports are blocked.
I have no trouble accessing the virtual machines (e. g. by ssh).

I followed the installation instructions on portainer.io.

Compose File:

```
version: '3.2'

services:
  agent:
    image: portainer/agent
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumes
    networks:
      - agent_network
    deploy:
      mode: global
      placement:
        constraints: [node.platform.os == linux]

  portainer:
    image: portainer/portainer-ce
    command: -H tcp://tasks.agent:9001 --tlsskipverify
    ports:
      - 9000:9000
      - 8000:8000
    volumes:
      - portainer_data:/data
    networks:
      - agent_network
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]

networks:
  agent_network:
    driver: overlay
    attachable: true

volumes:
  portainer_data:

```

Run command:

```
docker stack deploy --compose-file=portainer-agent-stack.yml portainer

```

The stack is successfully deployed and I can access the portainer UI as long as I'm in the local network. The UI is even accessible from other virtual machines, which are not part of the swarm.

But when I try to access the UI from my VPN, I get a timeout (SYN, but no ACK).
This happen for other container as well (e. g. I tried to test it with jwilder/whoami for different ports).

When I setup a container, with identical settings, without swarm, the service is accessiable via VPN.

# Answer
The problem was that the vpn network has the subnet 10.0.0.0/8 and the ingress network of docker swarm has the subnet 10.0.0.0/24. So there were a conflict.

Fix: Changing either the vpn subnet or the ingress network subnet.
> 1 votes

---
Tags: docker, docker-swarm
---


# Question
Title: What reasons should I NOT use a private DNS zone and CNAME services in my AWS/K8s environment?
I have a Kubernetes cluster in AWS, with apps that talk to AWS services like RDS, Elasticache, Elasticsearch, DynamoDB, etc.

For the services where it's available (Elasticache and RDS, and more recently Elasticsearch with a custom ACM certificate), I've considered making a private zone in Route53 and making CNAMEs for all the things. So instead of `app-production.789yuiahsdf.redis.elastitcache.aws.com` or whatever the Elasticache endpoint is, my app talks to `sidekiq.redis.app`. I'd use a pattern, maybe `<purpose>.<service>.<app>`, so I'd have `sidekiq.redis.app`, `cache.redis.app`, `primary.postgres.app`, `replica.postgres.app`, etc, etc.

The next step is having the app is configured by default to use these hosts. In development, staging, and production, they don't NEED any configuration (maybe it's still available), but the defaults should "just work" if the environment is set up properly.

**What are the downsides here? What am I missing?** To me, this seems sort of like simple service discovery and a reasonable idea. But reasonable ideas can sometimes bite you later on.

# Answer
> 1 votes
It seems a reasonable idea to me.
There migt be a few things you might want to check tho :

This article or this one. For example :

* the fact the that a private hosted zone is associated with a VPC
* there is some *DNS hostnames* and *DNS resolution* parameters on the VPC settings

> **enableDnsHostnames** : Indicates whether instances with public IP addresses get corresponding public DNS hostnames
> **enableDnsSupport** : Indicates whether the DNS resolution is supported.

* Only VPC resolver will resolve the private records (subnet range +2 for the ip of the VPC resolver, search for *reserved* ip here)
    + take care you didn't configure custom resolver and so wont be able to access your private records
    + think about the fact that you won't be able to resolve those records from outside the VPC (office for example) unless you manage to plug to the VPC resolver somehow

You could also give a look at Alias record ? Could give advantages like :

* create record that has the same name as the hosted zone
* not being charged for the queries (in opposite to CNAMEs)

These are few things I can think off right now. Hope this helps.

Cheers.

---
Tags: amazon-web-services, kubernetes, dns
---


# Question
Title: branch specific jenkins pipeline trigger
I am trying to trigger a jenkins pipeline job only when a pull request has been approved & merged to a specific github branch in our CI/CD implementation.

currently whenever i merge a PR to *release*, jenkins job that is created to get triggered when PR is merged to *master* is also getting triggered, while I only want *release* jenkins job to be triggered.

strangely *echo env.GIT\_BRANCH* cmd shows branch name as MASTER in *master* job, parallelly *release* job shows branch as RELEASE, when i only merged PR to release.

Things tried:

1. *Branches to build* feature in Jenkins
2. *when* condition in Jenkinsfile (its acting weird, both staging and production jobs are getting triggered when one branch is targetted)

Environment: *Jenkins ver. 2.176.3, Docker,Generic webhook trigger* for Jenkins

I'm convinced that when condition will work, but for me it isn't, following is my partial *when* condition in Jenkinsfile:

```
stage("Step 1: Build Docker"){}
stage("Step 2: Push to DockerHub"){}
stage("Step 3: Production Deployment"){
            when {
                expression { return params.current_status == "closed" && params.merged == true && env.GIT_BRANCH == "origin/master" }
            }
            steps{
                -----
                sh 'kubectl apply -f **.yaml'
            }
}

```

In my jenkinsfile I'm writing logic to deploy my docker images to kubernetes cluster, so all that i am looking for is to accurately trigger the job based on the branch.

Any suggestions on how to get it to work, what am i missing here?

# Answer
> 2 votes
Do you have 2 different jenkins jobs configured for master and release branches? Since github webhook event is sent to Jenkins irrespective of branch, both your jenkins jobs may be getting triggered by this github webhook event. And since both jobs are configured with separate branches, they may be checking out those branches during jenkins job execution which is why you may be seeing respective branches being printed in both jenkins jobs.

Checkout jenkins multibranch pipeline if you haven't already so you don't have to maintain multiple jenkins jobs for branches.

Now coming back to your Jenkinsfile code, you can try following:

1. Replace `env.GIT_BRANCH` with `env.BRANCH_NAME`
2. Use `allOf` inside when condition instead of `&&` -

```
stage("Step 3: Production Deployment"){
    when {
        allOf {
            expression { env.BRANCH_NAME == "origin/master" }
            expression { params.merged == true }
            expression { params.current_status == "closed" }
        }
    }
    steps{
        -----
        sh 'kubectl apply -f **.yaml'
    }
}

```

Note that github webhook will trigger the jenkins job for every branch push or PR merge event (irrespective of branch), so your jenkins job would have to handle multi-branch scenarios like explained in this official doc example.

---
Tags: jenkins, kubernetes, jenkins-pipeline, continuous-deployment
---


# Question
Title: Is there any Jenkins plugin for pylint results?
I have Pipeline which run Jenkinsfile. one of the stage is pylint:

```
python -m pylint --rcfile=.pylintrc --exit-zero ${MODULE} > ${WORKSPACE}/testreport/pylint.log

```

I know there was used to be violations plugin which is now deprecated. is there any alternative?

# Answer
> 3 votes
Jenkins accepts JUnit-formatted test results with the JUnit plugin, so you could try pylint-junit to output JUnit-formatted results (I have not tried this myself).

Also it looks like a very similar question was asked and answered over on StackOverflow.

---
Tags: jenkins-plugins, python
---


title: How to filter label_values in Loki?

text:
# Question
Title: How to filter label_values in Loki?
I want to create a query variable in grafana using Loki that returns all the possible label values of the label **baz** such that they only include label values that exist where the label **foo** equals **"bar"**. Looking at the docs, I came up with the following query for the variable:

label\_values(rate({foo=~"bar"}, baz)

However this returned all the possible baz label values and not only those that exist while foo="bar", basically the results are the same as:

label\_values(baz)

What am I doing wrong? thank you.

# Answer
After researching this, i've found an open issue on grafana's github. At the time of writing its still in the backlog.
> 2 votes

---
Tags: prometheus, grafana
---


# Question
Title: Can the Waterfall method leverage CI/CD+ and still be considered Waterfall?
Often it seems to be assumed or implied that DevOps is simply the Agile method expanded beyond programming to things like Operations and Configuration as Code, and so forth. So, this has left me wondering: Can a classic Waterfall method incorporate CI/CD and Configuration as Code and still be considered truly a Waterfall software development method?

# Answer
> 1 votes
I don't see why not.

Sequential SDLC models, like waterfall, are about the organization of steps. The requirements are "finalized" before extensive design begins. The design is "finalized" before the implementation begins. System testing happens after the requirements are satisfied. Some waterfall-like models, such as the sashimi model with some overlap between these phases or waterfall-with-subprojects, are multiple waterfalls after the overall system requirements and architecture have been completed.

There's nothing in the organization of these steps that would prevent continuous integration or configuration of code. Continuous deployment to a development environment is also possible, but continuous delivery or continuous deployment to production may or may not be possible, depending on the usability of interim builds before the requirements are complete. These practices can still be used once system implementation begins. CI and automated tests can help developers find issues during development before system integration and system testing activities begin. Configuration as Code can help with the configuration management of the system, allowing it to be versioned alongside the software system and rolled out to different test and production environments when it's time.

The key difference between highly sequential models and iterative and incremental models is responding to feedback, not the practices that can be used. Some practices may not make as much sense to use, especially if they are about getting and responding to feedback. If you have "finalized" requirements and "finalized" designs before you can start getting feedback on the system, stakeholder feedback will likely change those requirements and/or designs. Because of the scope of the work of requirements and design and the impact on the built system, late changes are expensive.

---
Tags: agile, waterfall
---


# Question
Title: In the AWS CLI how do I treat a special character as a string?
I'm trying to run an AWS CLI command for a resource with a ! in its name. I'm doing this from CentOS Docker instance running on my local device a MAC and if I run

```
echo "$SHELL"

```

it says it is using bash

Using echo 'test!' works for returning the value but testing in my CLI command it does not work

```
aws autoscaling put-scheduled-update-group-action --auto-scaling-group-name temp_asg --scheduled-action-name 'test!' --start-time 2020-12-06T12:00:00Z --min-size 0 --max-size 1 --desired-capacity 0 --region eu-west-1 --output json

```

returns bash: !\`: event not found

my AWS CLI version in the docker instance I'm running it from is aws-cli/1.16.251

# Answer
I found that if I put it in a script it sees it as a string and it's only an issue running directly from the terminal/command prompt but not an issue when running from a script with the header/shabang #!/bin/bash My final goal for this is for it to be part of a script so this has resolved my issue.

Im still not 100% on the issue when directly in the terminal and don't know if it's specific to the shell I'm using?
> 0 votes

---
Tags: amazon-web-services, aws-cli
---


# Question
Title: How to add label to Pull Request via Github API?
According to GitHub API user can add label to an issue using this POST request.

I tried using this request but with PR number instead to automatically set label on PR. Here is the function I wrote:

```
def setLabel (String repository, List labels) {
    try {
        def response = httpRequest httpMode: 'POST',
                    url: "https:[Repo_URL]/${repository}/issues/${CHANGE_ID}/labels",
                    authentication: 'ors_git_service_account',
                    requestBody: """{
                        "labels": labels
                    }"""
    } catch (e) {
        wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
            echo "\u001B[31magdSlack.setLabels: '" + e.toString() + "'\u001B[0m"
        }
        throw e
    }
}

```

And the response I get is `HTTP/1.1 400 Bad Request`

So I get that this request can't be used to labeling PRs.

My question: **Is there other method which could be triggered from Jenkinsfile, to add or change PR label?**

Closest thing to the question I asked was this question. Commenting API works on issues and PRs but that's not a case for labels.

# Answer
> 2 votes
I made it work by changing the way `labels` argument is passed into `requestBody`.

Turns out the list representation while interpolated into string is missing quotation marks around each list element.

```
def setLabels (String repository, List label) {
    try {
        String labelsAsString = "[\"${label.join('", "')}\"]"
        def response = httpRequest httpMode: 'POST',
                        url: "[REPO_URL]/${repository}/issues/${CHANGE_ID}/labels",
                        authentication: 'ors_git_service_account',
                        requestBody: """{
                            "labels": ${labelsAsString}
                        }"""
    } catch (e) {
        wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
            echo "\u001B[31magdSlack.setLabels: '" + e.toString() + "'\u001B[0m"
        }
        throw e
    }
}

```

---
Tags: jenkins, github, jenkinsfile
---