# Question
Title: Jenkins - load scripted parameters from a SCM repo
I am using all kind of parameters like "Active Choice Parameter", "Active Choice Reactive Parameter", "Active Choice Reactive Reference Parameter" that have a lot of Groovy code within them. My problem is that now I need to audit changes so I can link regression to code commits. I don't see an option to load the code from a SCM, how do I version this?

# Answer
As far as I can tell, there is no native functionality in Active Choice Parameters to load the Active Choice code from SCM. There are a couple ways to build this functionality yourself, however they're both clunky solutions that can be difficult to debug. (Unfortunately I can't copy any example code from my work right now because I'm at home on my personal computer. Remind me after the weekend is over and I might be able to find some example code snippets to go along with these suggestions.)

* Your Active Choice scripts can clone a repo, read in a file, and eval it. This is made quite difficult by the fact that Active Choice scripts don't have any access to the Pipeline DSL, so you can't use any of the steps you would normally use in Pipeline code to clone a repo like `scm` or `git` or `withCredentials`. There are also many other considerations you'll need to take into account which you normally can ignore in Pipeline code, like ensuring that you run the clone inside a temporary directory and so on. Ultimately I found this too difficult to do so I have been using the second solution instead:
* You can write a separate "meta" job that updates the parameters of your actual job and injects the Active Choice groovy scripts into its parameter configuration. I set this job to run on a hook on the repo which contains my Active Choice scripts, so every time I push to that repo, it updates the Active Choice groovy scripts. This does rely quite heavily on the Jenkins Java API (which is available in Active Choice groovy scripts), so you'll need to get familiar with the ins and outs of that API. That API can be quite a maze, especially for Pipeline-related endpoints (since Pipeline source code is heavily modularized and spread out across many repositories and API docs).
> 1 votes

# Answer
I've not used these plugins but I am using pipelines and pipeline libraries (https://jenkins.io/doc/book/pipeline/shared-libraries/).

My Jenkinsfile is now dead simple basically made of an import, I define a map for project specific parameters and call the function from the import with the map :

```
@Library('lib-pipeline')

def config = ["project_code":"ProjA",
          "phase_code":"prod",
          "build_NET":"YES",
          "build_mono":"NO",
          "run_tests":"YES",
          "run_tests_coverage":"YES",
          "p4_credential":"MY_CREDENTIAL"
          ]

BuildWithMapConfig(config)

```

All the actual code is in a git repo where we can track changes properly. you can set a branch in your import

```
@Library('lib-pipeline@develop')

```

This coupled with the retry option in Jenkins where you can modify the Jenkinsfile just for that run makes it super easy to test variants in this pipeline.

Having it all in a separate library I imagine you could de-couple the groovy script in a way that makes them unit testable on their own. You could add a pipeline to that project to run these tests and other validations too.

Since I've never used these plugins I'm not exactly sure this is what you are looking for, but if I had to add these functionalities in my pipeline that would be how I would do it.
> 0 votes

---
Tags: jenkins, jenkins-pipeline, jenkins-plugins, jenkinsfile, jenkins2
---


# Question
Title: How to create unique GPG Keys for different environments / projects
After searching and reading various documents it remains unclear to me as to an effective/straightforward manner to create/maintain multiple sets of GPG Keys.

I have a project that needs unique GPG Keys per environment and each user has their own GPG Key. Thus each server (environment) needs unique GPG keys.

I would envision the most secure and best practice is for each environment would have its own `gpg --gen-key` results for which to base its own private and public keys. From there an admin could add a user to each environment as needed.

Or am I just missing the point all together?

# Answer
> 1 votes
If you want to create separate key pairs that are not dependent on your personal keys, the easiest way is to use a separate GPG home directory for each. For example, to create keys for "projectB", first create an empty directory, then tell gpg to use that dir as its home:

```
mkdir projectB-gpg
gpg --homedir ./projectB-gpg --gen-key

```

That will do what you want, although you will now have the problem of distributing the private keys and passwords securely to each environment.

---
Tags: security, encryption, gpg
---


# Question
Title: 'find' command suddenly not working in windows hosted agents
In the YAML file defining our ADO build pipeline we have the following section

```
- bash: |
    pip install pylint
    find preprocessing/ subtyping/ visualisations/ -name '*.py' | grep -v hmm | grep -v /test_ | sort | xargs pylint
  displayName: 'Run linter'

```

At some point in the last week this stopped working. It still works on an `ubuntu-latest` hosted agent, but on Windows (either `windows-latest` or `vs2017-win2016`) it now fails with the message

> FIND: Parameter format not correct

We have not changed anything, but our build process now fails.

* What has changed to cause this failure?
* Why does it only fail on Windows?
* How might I diagnose the problem?
* Is there anything wrong with our call to bash's 'find' command?

# Answer
> 2 votes
Find is a command in Windows that does very different thing to find in a posix shell.

And that would be the error you would get if you ran the Windows find (usually Windows find is located at `C:\Windows\System32\find.exe`

# Answer
> 1 votes
Your PATH may have somehow changed and you're now hitting the Windows `find` instead of the \*nix-compatible one.

Try specifying the full path, i.e. `/usr/bin/find` (that's what I see on my windows bash shell when I check with `which find`) instead of just `find` in your build process command.

---
Tags: azure-devops, azure-pipelines
---


# Question
Title: windows 10 vs windows server 2016 as jenkins slave
The builds are running locally in my Windows 10 OS successfully. Can I run the same builds in Jenkins slave with Windows Server 2016? Will there be any issues during the build or should I go for Windows 10 OS for the slave setup?

# Answer
Unless you do something distro-specific (i.e. something which depends on the specific version of Windows) there should be no issues.
> 1 votes

---
Tags: jenkins, windows
---


# Question
Title: How do i notify GitHub pull request for each stage of a parallel Jenkins pipeline?
We have a parallel Jenkins pipeline script which deploy and run three kind of tests in parallel. We have to notify the status of each stage to GitHub pull request. Can anyone help me to get this?

```
def jobs = [
    [
        "name" : "LegacyUnitTests",
        "runFolder" : "recipes",
        "run"   : { -> sh "docker-compose -f docker-compose/docker-compose-maven.yml -f docker-compose/docker-compose.yml run maven-unit-test" },
        "report": { -> junit testResults: "docker-compose/volmnt/reports/*.xml" },
    ],
    [
        "name" : "AutomationTests",
        "runFolder" : "automation",
        "run"   : { -> sh "../run_automation_tests.sh" },
        "report": { ->
            junit testResults: "reports/junit/*.xml"
            allure([
                includeProperties: false,
                jdk: '',
                properties: [],
                reportBuildPolicy: 'ALWAYS',
                results: [[path: '/reports/allure']]
            ])
        }
    ]
]

def parallelStagesMap = jobs.collectEntries {
    ["${it.name}" : generateStage(it)]
}

def generateStage(job) {
    return {
        stage(job.name) {
            dir(job.runFolder) {
                try {
                    job.run.call()
                    setSuccess(this, job.name)
                }
                catch (err) {
                    setFailed(this, job.name)
                }
            }
       }
   }
}

pipeline {
    agent {
        node {
            label 'pr-slave-test'
            customWorkspace "/var/lib/jenkins/workspace/${JOB_NAME}_${BUILD_NUMBER}"
        }
    }
    post {
        always {
            //Reports
            script {
                jobs.each {
                    j -> j.report.call()
                }
            }//Cleanup
            cleanWs()
        }
    }
    stages {
        stage('Pre-Build') {
            steps {
                 script {
                    //set status as pending
                    jobs.each {
                        j -> setPending(this, j.name)
                    }
                    //checkout all repo
                 }
            }
        }
        stage('Build') {
            steps {
                dir () {
                    sh "echo \"Building\""
                }
            }
        }
        stage('CI') {
            steps {
                script {
                    parallel parallelStagesMap
                }
            }
        }
    }
}

```

I want to notify GitHub pr for each stage automation and legacy unit test status as pass fail as a GitHub check status

# Answer
> 1 votes
I don't think I can help you with this, but I think I can suggest you where to look for a relevant information.

1. You can report any status check to your PR using Status API (https://developer.github.com/v3/repos/statuses/)
2. You can configure which Status checks are required from PR (https://help.github.com/en/github/administering-a-repository/about-required-status-checks)
3. Since pipeline is actually groovy code, calling Status API should not be a challenge. (Example with CURL - https://www.openmakesoftware.com/restful-json-api-calls-jenkins-pipeline/, example using native groovy - https://www.deployhub.com/native-groovy-api/)

---
Tags: jenkins-pipeline, github
---


# Question
Title: What is the best way to find the Auto Scaling Group of an ECS cluster?
We are looking to inspect the ASG EC2 CloudWatch metrics such as CPU and Memory, since it includes an aggregate of all the ASG instances.

Given that we know the ECS cluster, or the ECS service name. Which API calls would be needed to figure out the name of the Auto Scaling Group and its CloudWatch metrics?

# Answer
> 2 votes
Example in AWS cli that should work to get the ASG name

```
a=curl 'http://169.254.169.254/latest/meta-data/instance-id'; aws autoscaling describe-auto-scaling-instances --instance-ids $a --query 'AutoScalingInstances[*].AutoScalingGroupName'

```

# Answer
> 0 votes
Here I ran for ap-south-1 region-

a=`curl 'http://169.254.169.254/latest/meta-data/instance-id'c ;
 aws autoscaling describe-auto-scaling-instances --instance-ids $a --query 'AutoScalingInstances[0].AutoScalingGroupName' --region ap-south-1`

---
Tags: amazon-ec2, amazon-cloudwatch, amazon-ecs
---


# Question
Title: Prometheus-operator - detection of expiring certs failing
I had a situation yesterday where my K8S master api cert has expired and I had Prometheus-operator active in the past weeks, but neither the 24 hours, neither the 7 days alert has triggered. I went to the dashboard and made the original querry, I got nothing. I cut it out and mod it to apiserver\_client\_certificate\_expiration\_seconds\_count{job="apiserver"} \> 0, I got the result of all nodes, I checked the timers and moded it to apiserver\_client\_certificate\_expiration\_seconds\_count{job="apiserver"} \> 14000000 so I wanted one that is off to be cut and it was, that doesn't help me, but I think there is a problem with the alert, anyone else fought that? https://github.com/kubernetes-monitoring/kubernetes-mixin/tree/master/runbook.md#alert-name-kubeclientcertificateexpiration If this is supposed to monitor all endpoints that make a request to the api server for their certificates then this failed as I didn't get an alert for the expired certificate.

# Answer
The alert is broken, it is fixed in further release version of the mixins, we need to apply on(job) infront of the histogram to fix it. Example: apiserver\_client\_certificate\_expiration\_seconds\_count{job="apiserver"} \> 0 and on(job) histogram\_quantile(0.01, sum by (job, le) (rate(apiserver\_client\_certificate\_expiration\_seconds\_bucket{job="apiserver"}\[5m\]))) \< 60432131800 and yes, that means your certs are not being tracked...
> 0 votes

---
Tags: kubernetes, prometheus
---


# Question
Title: Condition to skip a test when running in a container
I'm writing an Inspec profile which has a specific control that I want to skip *if the control is running inside a docker container*. This looks like:

```
control 'ssh daemon' do
  impact 'critical'
  only_if('not in docker') do
    condition_expression
  end
  describe service('sshd') do
    it { should be_installed }
    it { should be_enabled }
    it { should be_running }
  end
end

```

I need the `condition_expression` to return false when in a container. Is there an elegant way to do this with ruby or inspec without shelling out?

# Answer
> 5 votes
In Ruby you can use this function:

```
# return true if we are inside a docker container
def in_container?
  return File.file?('/.dockerenv')
end

```

---
Tags: docker, inspec
---


# Question
Title: Problem on gitlab-runner: cannot lock ref [...] Another git process seems to be running in this repository
I got a problem on a gitlab-runner after pushing several commits:

```
Running with gitlab-runner 11.4.0 (8af42251)
   on GITLAB-RUNNER 58c31dfa
 Using Docker executor with image registry.git.rwth-aachen.de/luechow-group/inpsights/gnu:7.3.0 ...
 Pulling docker image registry.git.rwth-aachen.de/luechow-group/inpsights/gnu:7.3.0 ...
 Using docker image sha256:8c48f31ac37d239cf7c072961068e85dd0af222604461b7c0df905a45e900877 for registry.git.rwth-aachen.de/luechow-group/inpsights/gnu:7.3.0 ...
Running on runner-58c31dfa-project-12102-concurrent-0 via GITLAB-RUNNER...
00:05
Fetching changes...
 HEAD is now at 15dd3f8 .
 error: cannot lock ref 'refs/remotes/origin/develop': Unable to create '/builds/luechow-group/inPsights/.git/refs/remotes/origin/develop.lock': File exists.
 Another git process seems to be running in this repository, e.g.
 an editor opened by 'git commit'. Please make sure all processes
 are terminated then try again. If it still fails, a git process
 may have crashed in this repository earlier:
 remove the file manually to continue.
 From https://git.rwth-aachen.de/luechow-group/inPsights
  ! 62d2cd4..f2bb2fe  develop    -> origin/develop  (unable to update local ref)
    15dd3f8..0c2b081  feature/ElectronSelectorRebase -> origin/feature/ElectronSelectorRebase
 Auto packing the repository in background for optimum performance.
 See "git help gc" for manual housekeeping.
 error: cannot lock ref 'refs/remotes/origin/develop': Unable to create '/builds/luechow-group/inPsights/.git/refs/remotes/origin/develop.lock': File exists.
 Another git process seems to be running in this repository, e.g.
 an editor opened by 'git commit'. Please make sure all processes
 are terminated then try again. If it still fails, a git process
 may have crashed in this repository earlier:
 remove the file manually to continue.
 error: failed to run reflog
 ERROR: Job failed: exit code 1

```

Which command do I have to use to delete the `.lock` file in the docker container and to save this change?

# Answer
The easiest solution for me was to execute

`docker container prune`

on the runner machine. The command removes all stopped docker containers and the `.lock` files therein. Running a pipeline from gitlab.com then starts a new container. (Note that all caches will be lost).
> 3 votes

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


title: How to handle resource creation?

text:
# Question
Title: How to handle resource creation?
We're moving from a .NET monolithic application to a microservices architecture hosted on Azure.

Until now, we only had one build definition on TFS and a release definition for each environment (development, staging and production). All the Azure resources needed to deploy to each environment were created manually. We want to automate this part.

How's the recommended approach to handle new resources setup? Do you just put steps in the release pipeline that will create the needed resources when they don't exist? Or do you have a separate pipeline that's solely responsible for creating all the resources for a new environment?

# Answer
You can use **Terraform for azure** to handle the dynamic creation of azure resources in the release pipeline in Azure DevOps. Terraform maintains a state file for all the created resources after a run.

If the script is run multiple times, it ignores already created resources unless there are any properties updated and created new resources.

FYI, follow below link for a quick example Terraform example
> 1 votes

---
Tags: azure-devops, microservices, release-management, tfs, environments
---


title: validation block iteratively

text:
# Question
Title: validation block iteratively
This validation block works for a single input variable.

```
variable "mytestname" {

     validation {
        condition = length(regexall("test$", var.mytestname)) > 0
        error_message = "Should end in test"
     }
}

```

I need it to work inside a for\_each - or have some workaround to accomplish this. The issue is that there is a restriction on the condition statement - the condition HAS to take in the input variable itself (i.e. - it cannot accept an each.value)

```
variable "mytestnames" {

listnames = split(",",var.mytestnames)

for_each = var.listnames

     validation {
        condition = length(regexall("test$", each.value)) > 0
        error_message = "Should end in test"
      }
}

```

The above snippet does not work. I need a way I can iterate over a list of values and validate each of them using the validation block. There must be a way to do this without a validation block...??

# Answer
It sounds like your goal is to have a variable that takes a list and to validate each of the elements of that list. If that's true, then the approach would be to write an expression that returns true only if *all* of the elements are valid. For example:

```
variable "names" {
  type = list(string)

  validation {
    condition     = can([for v in var.names : regex("test$", v)])
    error_message = "All names must end with \"test\"."
  }
}

```

The above relies on the fact that `regex` will fail if the given string doesn't match the given pattern, and that the `for` expression will fail if the given expression fails for any `v`. `can` then captures the failure and returns `false`, making the validation fail.
> 2 votes

---
Tags: terraform
---


# Question
Title: How to make .DACPAC from Azure Sql Server using Azure DevOps release pipeline?
I'm using Terraform to create my environment and I'd like to deploy Azure Sql Server along with other things. I use terraform so I can easily destroy all deployed things and reduce costs when I'm not using them.
So, I decided that I can add Azure Sql Server into my Terraform file but I need to store my information into backup file so I can restore it with "Azure SQL Database deployment" task from pipeline. Hovewer, I haven't find any indication that it is possible to create a .DACPAC from within Azure DevOps.
So, is there a way to create and save a backup of my database (preferrably, into a blob storage) from Azure DevOps pipeline? I looked into azure shell (az sql database), but haven't find anything of value

# Answer
> 2 votes
Ok, after researching some more time, I've found this gem https://markheath.net/post/backup-restore-sql-database-azure-cli. In this article author uses `az sql db export` and `az sql db import` to save database into BACPAC and restore it back on the clean database. But here comes a pitfall - Azure CLI task v1.0 uses **CMD** so it's not easy to translate from **Bash** syntax to **CMD**, and Azure CLI task v2.0 *preview* which has option to choose **Bash** as an interpreter doesn't have az installed (it's probably a bug and already has a post on uservoice) so one needs to rewrite the script into **Powershell** if they want to use it.
So, it's not completely what I was looking for but it does its job.

---
Tags: azure-devops, azure, azure-pipelines
---


# Question
Title: What are some reasons for using an Ansible role for Certbot vs. Ansible's native `acme_certificate` module?
To get Let's Encrypt HTTPS certificates for their Web sites, I'm aware of quite a few folks using a particular role, which wraps Certbot, a standalone application not native to Ansible.

There is, however, a native Ansible module called acme\_certificate, and at least one accompanying role that wraps it.

It seems to me that it would make sense to native Ansible modules whenever possible, but are there reasons for not doing so in this particular case?

# Answer
Thanks for linking your question. Here's the github thread for reference: https://github.com/geerlingguy/ansible-role-certbot/issues/87

There are many different ways to get certs from a CA. certbot (what this repo uses) is just one of the ways which uses letsencrypt as a certificate authority. acme\_certificate is more generic and if you can't use letsencrypt then it might be a good tool to check out for http-01, dns-01 and tls-alpn-01 challenges.

Certbot is a great way to manage certs from letsencrypt, so if you're needs are fairly standard this is a good choice. It's a higher level package and will also handle auto renewal (assuming you enable it).

it is possible to do renewals with acme\_certificate. You could do something similar with letsencrypt https://docs.ansible.com/ansible/2.5/modules/letsencrypt\_module.html . certbot just handles a lot of this for you, specifically for letsencrypt.

Personally I think using certbot to help manage certificates is simpler, but that's up to you. certbot is an application that handles the verification process for with the certificate authority, which is very handy. With acme\_certificate you'll essentially be doing that yourself. It also automatically can set up automatic renewals which is very nice.
> 6 votes

# Answer
Others have pointed it out already; Certbot makes it easy to handle certificates while `acme_certificate` module is more flexible and transparent.

## Acquire Certificate

To request the ssl certificate with `acme_certificate`, there are good examples on DigitalOcean or on Reddit. These examples boil down to following tasks:

1. Ensure you have a private key for your acme account. (module `openssl_privatekey`)
2. Ensure you have a private key for your certificate. (module `openssl_privatekey`)
3. Ensure you have a certificate signing request. (module `openssl_csr`)
4. Then a challenge is requested from letsencrypt. (module \`acme\_certificate')
5. One of the challenges `dns-01`, `http-01` or `tls-alpn-01` is implemented.
6. The certficate from letsencrypt is requested. (module \`acme\_certificate')
7. (optional) The challenge implementation is removed.
8. The server configuration is updated with the ssl certificates.

With Certbot you can have all these steps in one handy command. They provide instructions for any platform.

```
sudo certbot --nginx

```

Module `acme_certificate` is Ansible native and a playbook with all these steps is only written once. The tasks in the playbook are transparent and you have the certificates and keys for your server configuration at hand. With Certbot you have to know the directory `/etc/letsencrypt/live/my.domain.com` wherein those artifacts are generated.

## Renew Certificate

A crucial point is the responsibility for certificate renewal. Above Certbot command has already created a cron job which checks the validity of the certificate and renews it if required. If the certificate is managed with Ansible you have to run an Ansible playbook for renewal.

Letsencrypt certificates are valid for 90 days, so the renewal process gets automated. For the renewal, above Ansible playbook works, it does the renewal as well. However, it is advised to create a new csr (3) and certificate key (2) when a certificate is renewed. Handling this properly, the playbook will grow quite a bit.

On Ubuntu, above certbot command has already created a cron job which handles certificate renewal, so nothing else needs to be done.

## Conclusion

There are roles in Ansible Galaxy for Certbot and `acme_certificate` module. Personally, I like `acme_certificate` module for its transparency and because it's an Ansible native solution. However, I run Ansible from my personal notebook and do not want to remember running a playbook for certificate renewal. Therefore, I have installed Certbot which runs on the host and does the renewal without an external trigger.
> 1 votes

# Answer
I have been writing a few playbooks and roles to automate the installation of servers in my network, but the initial request for a certificate from LE has always proven cumbersome. E.g. For a dns-01 challenge, your dns configuration must have been propagated upstream or certbot will fail.

I am now considering to use the native acme\_\* modules to acquire the initial certificate(s) and then generate services on the host (using more generic ansible modules) to let certbot manage the renewal.

Implementation of additional functionality such as force-renewal (which I didn't consider before the 29 Feb 2020 bug in LE) and revocation of certificates is not yet very clear to me, but I'm leaning towards the native module.
> 1 votes

---
Tags: ansible, certbot
---


# Question
Title: Download an artifact from Nexus to Jenkins
I use `ssh username and private key` auth to download sources from Git, build the artifact and deploy it to my nginx server. Now I need to download an artifact as a zip file to Jenkins agent, prepare it and deploy to my nginx server. I can only access Nexus using username/password pair.

Is there a way to run `scp mynexus.com/my_artifact.zip ~/my_artifact.zip` and pass username with password from Jenkins credentials?

# Answer
There are a few ways to do this, but by far the easiest is to put your credentials (either username/password or ssh keypair) into the Jenkins built-in credentials store and then use the sshagent step in your Pipeline script:

```
sshagent(credentials: ['my-credentials']) {
  sh('scp mynexus.com/my_artifact.zip ~/my_artifact.zip')
}

```

You may need to install the SSH Agent plugin to be able to use this step; I'm not sure if it's part of the default set of Pipeline plugins or not.
> 1 votes

# Answer
Create String parameter `artifactID`, Password parameter `NexusUser` with username and Password parameter `NexusPassword` with nexus password.

`curl -v -u $NexusUser:$NexusPassword -o ~/tmp_dl/distr.zip https://my_nexus_url.com/nexus/content/repositories/${artifactID}/distrib.zip`
> 1 votes

---
Tags: jenkins, nexus, ssh
---


# Question
Title: Auto-managed docker-compose volume not shared among containers
I have a bit of hard time understanding the way `docker-compose` handles auto-managed volumes. Here is an example `docker-compose.yml`

```
version: '3.7'
services:
  one:
    image: alpine
    command: sh -c 'echo one >> /data/db.txt && cat /data/db.txt | wc -l'
    volumes:
      - /data

```

And here is what I get (`docker-compose` logs stripped out)

```
$ docker-compose up
1 # as expected

$ docker-compose start
$ docker-compose up
3 # as expected

$ docker-compose run one
1 # why ? I expected 4

```

So it seems the volume is not shared between containers of the same service (in this example, the service `one`). Actually a new volume seems to be created every time `run` is used

```
test $(docker volume ls | wc -l) -eq 0 # ensure clean env

repeat 10 docker-compose up
test $(docker volume ls | wc -l) -eq 1 # works

docker-compose down && docker volume prune -f # cleanup

repeat 10 docker-compose run one
test $(docker volume ls | wc -l) -eq 1 # fails, result is 10 instead

```

The `docker-compose` documentation does not really help, the only explanation seems to be

> Just specify a path and let the Engine create a volume
>
> ```
> volumes:
>   - /var/lib/mysql
>
> ```

I do not encounter this issue when using named volumes (*e.g.* `data:/data`). So **why is a new volume created for new containers of the same service ?** And what is the point of such behavior to be the default ?

*N.B. I know I should use explicitly defined volumes instead, but I want to understand the default behavior, and why it is this way*

> `docker` and `docker-compose` version info https://pastebin.com/8TuFCg2i

# Answer
Define the volume in the following way

```
volumes:
  - ${local_path}:/data

```

or using docker volumes

```
version: '3.7'

volumes:
  db-data:

services:
  one:
    image: alpine
    command: sh -c 'echo one >> /data/db.txt && cat /data/db.txt | wc -l'
    volumes:
      - db-data:/data

```
> 1 votes

---
Tags: docker, docker-compose, containers, volume
---


# Question
Title: Bitbucket pipelines: Deployment destination dependent on commit author
I'd like to create a deployment pipeline triggered on PR creation that would deploy to e.g. 'staging1' environment if it's my commit and 'staging2' if it's a commit of other team member (the idea is for each team member to have his/her own environment assigned, but deploy using a shared parametrized pipeline). Is it possible to achieve this and if so, then how?

# Answer
> 1 votes
```
the idea is for each team member to have his/her own environment assigned, but deploy using a shared parametrized pipeline

```
1. You could use definitions for the steps for each environment.

```
definitions:
  steps:
    - step: deploy to staging1
        script:
          - echo "Staging 1"
    - step: deploy to staging2
        script:
          - echo "Staging 2"

```
2. Then just express each colleague branch and restrict his commits to just this branch. For each of the branches you could call your needed definitions.

```
branches:    #these will run on every push of the branch
    feature/john.b:
      - step:
          # call needed definition step/s
    feature/pavel.m:
          # call needed definition step/s

```

This gives u flexibility to express multiple definitions steps for one person if needed.

---
Tags: deployment, continuous-deployment, cicd, bitbucket, bitbucket-pipelines
---


# Question
Title: Custom inventory file failing to parse properly
I've got the following production inventory file (`playbooks/production.yaml`) for Ansible:

```
all:
  children:
    control:
      moriarty.server.com
      toby.server.com
    managed:
      sherlock.server.com

```

Based on what I'm reading online, it looks like it should be correct, and I can't find any syntax errors in the file using a YAML linter. However, when I run `ansible-playbook` on my local machine, I get the following error:

```
$ ansible-playbook -i playbooks/production.yaml --extra-vars target=moriarty.server.com playbooks/create-server.yaml
[WARNING]: log file at /var/log/ansible.log is not writeable and we cannot create it, aborting

[WARNING]: Skipping 'control' as this is not a valid group definition

[WARNING]:  * Failed to parse /Users/username/infra/playbooks/production.yaml with auto plugin: no root 'plugin' key found,
'/Users/username/infra/playbooks/production.yaml' is not a valid YAML inventory plugin config file

[WARNING]:  * Failed to parse /Users/username/infra/playbooks/production.yaml with yaml plugin: control is not a known host nor group

[WARNING]:  * Failed to parse /Users/username/infra/playbooks/production.yaml with ini plugin: Invalid host pattern 'all:' supplied, ending in ':' is not allowed, this
character is reserved to provide a port.

[WARNING]: Unable to parse /Users/username/infra/playbooks/production.yaml as an inventory source

[WARNING]: No inventory was parsed, only implicit localhost is available

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

[WARNING]: Could not match supplied host pattern, ignoring: moriarty.server.com

PLAY [moriarty.server.com] ************************************************************************************************************************************************
skipping: no hosts matched

PLAY RECAP **************************************************************************************************************************************************************************

```

I'm at a loss, since it looks to be valid YAML. Do I need to format it some other way when I have groups in this manner?

# Answer
The keyword `hosts` is missing. Also colons `:` are needed after the hostnames. Fix the syntax, for example

```
all:
  children:
    control:
      hosts:
        moriarty.server.com:
        toby.server.com:
    managed:
      hosts:
        sherlock.server.com:

```

See How to build your inventory.
> 5 votes

# Answer
Just add `hosts` before every block of hosts. I.e., under the group level, you should have `hosts` directive

See ansible source code example:

> `- Hosts must be specified in a group's hosts:`

Working inventory.yml:

```
all:
  children:
    control:
      hosts:
        localhost
        127.0.0.1
    managed:
      hosts:
       localhost

```
> 1 votes

---
Tags: ansible, yaml, ansible-inventory
---


# Question
Title: CloudFront -> ELB -> Pod running Gunicorn
Can anyone tell me if there's a "killer" reason to put NGINX in front Kubernetes pods running Gunicorn?

externally, I have CloudFront hitting an ELB which in turn engages the pods running Gunicorn with my Django based API server.

Since Caching is handled by CloudFront, and it's flexible enough for routing rules -- is there any good reason to add NGINX to the mix?

# Answer
Nginx will help you in performing the below items if you need some of them, Then I would say it make sense to add it to the stack

* Optimize the caching (you can also cache dynamic content.
* Restrict access to the services (based on ips).
* Implement basic auth for some services.
* Load balancing traffic between different posds or services.
* Rewrite URLS.
* Pass extra headers or configs to the backend services.
> 1 votes

---
Tags: nginx, amazon-cloudfront
---


# Question
Title: How do I package a jar and a Linux VM to run in Windows?
I'm new to DevOps so please forgive my ignorance. I have inherited a Win10 Java app that is currently run by pressing play in NetBeans. It makes API calls to a server running in a Linux VM.

What I'd like to know is how can I bundle this together and create an application that can be installed and run'out of the box' in win 10? Also, if possible, as a web service.

I'm just after pointers on how to start.

# Answer
Generally people go the opposite direction and try to get more to run on Linux as it is generally cheaper (e.g. license free). Also, Windows 10 is more of a personal workstation (vs Windows Server). So, it seems like it may be a short term strategy (unless you're just learning on your own).

Having said that, the most DevOps standard way to do this would be to:

* Install Docker on your Windows 10 PC. Docker (in layman terms) lets you run apps on top of slimmed down operating systems of various kinds in a portable manner.
* Dockerize the application(s) running on the Linux server. You can start off with some slim linux variant like Alpine and just add what you need.
* While you're at it, just Dockerize your windows 10 Java app at the same time and start running it from command line rather than NetBeans.
* Now, you can run it all on Windows or Mac Or Linux (or kubernetes) with ease.

This assumes the server-side app is not a Java or otherwise portable app. If it is portable, you can just run it locally and forget all this (although all of this is still a good idea).
> 1 votes

---
Tags: linux, windows, java, vm
---


# Question
Title: Terraform: can't connect to AWS provider using shared config file or static variable
I'm trying to use terraform to manage AWS resources and trying to set up the credentials configuration. I'm following the official documentation: https://www.terraform.io/docs/providers/aws/index.html

My first idea was set a shared credentials file so I configure it:

* ~.aws/credentials

```
[default]
aws_access_key_id=****
aws_secret_access_key=****

```
* ~.aws/config

```
[default]
region=us-east-1
output=json

```
* app/main.tf

```
provider "aws" {
    region = "us-east-1"
    version = "~> 2.0"
    profile = "default"
}

terraform {
    backend "s3" {
        bucket = "example-bucket"
        key    = "terraform-test.tfstate"
        region = "us-east-1"
  }
}

```

When I run `terraform init` I receive the following message:

```
Error: No valid credential sources found for AWS Provider.
        Please see https://terraform.io/docs/providers/aws/index.html for more information on
        providing credentials for the AWS Provider

```

I have already tested the credentials using aws cli and it's working perfectly.

After that, I tried to configure static credentials in main.tf like this:

```
provider "aws" {
    region = "us-east-1"
    version = "~> 2.0"
    access_key = "****"
    secret_key = "****"
}

```

Same error...

I decided to test with environment variables and then it worked. But now I want to know why I could not configure with static variables or shared config file. All this cases was described in the official docs, what am I doing wrong?

# Answer
The easiest way I've found to properly set credentials for my local runs and remote terraform cloud runs is to use environment variables. Before running set the environment variables for

```
AWS_ACCESS_KEY_ID
AWS_SECRET_KEY
AWS_DEFAULT_REGION

```

This should allow you to run in both Linux, PowerShell or even remote runs in Terraform cloud without issue.

I've gone between various approaches and this has provided me the easiest workflow. If you're doing this in AWS directly then of course you could use IAM instance role and avoid credentials altogether. This wouldn't allow you to keep the same workflow for local and remote though.
> 1 votes

---
Tags: amazon-web-services, terraform
---


# Question
Title: Weird requests filling apache access logs
I'm running a public apache2 webserver. I'm getting a lot of this kind of requests on my webserver:

91.251.142.16 - - \[07/Mar/2020:19:58:09 +0100\] "\xe8\x95h\x8d\xf0\x1d\x99Q\xb8~\xb5\xbc\xa7\*\x1c\xe1\x07\x10\x0c\xce\xc4\xb5\<\xa3\xfb8\xf1\x19\xcb&N\xbc0\xdd\xad@\x82\xd0.\x8f\]n&:\x8d\xcfnW\xe7\x11\x803o{X\xd43oPo\xbc\xb19\x94\xb3\xb5\xb9\x15k\xcf\x06\xe1\x19h\xb3c`b\xc9\xf2\xbe\xa4A\vX\xc9\xd3Rx\x0c\xfbzIFA\xd6\xe7C?2\xdd\xbe\x1d\x96^\t\xcfq\xe5\xaf7Cl\xab\xc7\x18\x81:^p\xcf\x10!\x95\r2T\xc3b\xa1r\xcdNSS\xc4R;-\x98\xef\xf25\xc2\x90\xa2\x95\xfc\x9e/\xdcy\xc0\x8e\xa2I\x0fd\xdb:\b\xb2\xf0\xe3V\xd1\xaet0c\xbb\xc8\xe7\xc6\x98>\x82\x83K\xdcp\x7fA\x9f\xc6\xe1\xfc\xf6\x10#\x13\x95\xd6\x98\x80\xe2\x1b\x9b\xfe\xa4\xda^_\xa6\x04\xf3\x86;y\x13\xfb\x8d\xb8\xb6\xee\xc2qT\xef\xed\xcf\xe5L\x8f\xf4T-Y\x82\x84n!\xc4\x8c\x02QUP]\x99((\xb5\xf07+\xfeT\xd8K\xf2y0\x1a\xd1\xf4z4\x13_B\xcer\xe4\x86@]\xca\xc5o\xaemm\x89\xf1\xaa\x84z\xfa\x82\xc6\xd2\x15\xc8\xf0$'x\xc1\xcc\xc4r\xf8\x9cI\xe5^\xfa\xd1\xa3\x9c\x85\xbb'W\xb2\xa1\x17 l\xa3\xfd \t9\xc5\x94(\x9f3\xf818$\x17b\x17\xb2\x8f!4R\x80\x82\x92*\xf3\xd4\x83h\x99\v\xa7I\"\x9c\xe6\xcfN\xab\xee\x834y\xe1\x11\xecf1\vZ\xc0\xaa9\xaf\x86RGM\xe3\x80\x9e\x9eH8\x13P2\x15\xe4$\xdfAM;\xb8\x99\x9eO\xec \xfc\xa3Mo\x81M\x9d\x851\xd3g!\x90\xdd\xb3\xb9U^\xd1\xa3\xc6\xe1G\xd9\x1d\xa2\xc0/\xd7\xce\xefM\xbc X9\xa0M\xb4\x94\xdbY>g\xc0$S\xdc\x87.\xbc\x95\xf7\xa1ct\xd6\xa9\xf3\x16\x91\x99\x9ep\xe0\xcd[\xd5\xf7\xbdn\xd2\\!\xca\x8e\x13LG\xbc\xa3\x9d\x01\x1awl\xc1\v\xaf\x02G\x05\x02\xddl\"m\xc4z\xef\xca\t\x12S\xf8\xf6\xbbRo\xc9\xe55y\xaa#\xd0\xd4\xa3Y\x8b\xd48f\xcd\xe0gaj\x7f;\v\v\x8c<\xa0^\xcd\x15\xfcAT\xdc\x81H,\xd6Y\x88\"\xc8zWv^jS\xfb|Cz\x84b\x88;\xf2\xc2o\x1ay\xc9\xf2\x1a\x01\x7f\xc6\xc2%/\x11j\x825|:\xc2\xc9-\x9a{Sx\"\xa8A\x06'\x0e\xa7\xe7UK\x11\xbc\x1a\xfeU\x0f\x82l\x9c\x0e\x94\x87\xf8\xed_\x1c\xd0\xee,\xb6>\x97\x17\xe3pk\xa0\xed\xdaKh^\xc9h,\xfc3\xa9p\xb3\xea\xf2h\xb4\xf5>\x1e\x9b\x18w\xf3\xb5\xd0\x84u\xcd! \xf5\xb0\xbd\n" 400 0 "-" "-"
91.251.142.16 - - [07/Mar/2020:19:58:14 +0100] "\xab\xa1\x8d\xffGu.\xae\x94\xdb\x16@\x1d\x01\xc0M\x19\xae\xf8\xabKIE\xe2\xb2\x11;\x80\xf2\x9dnM-\xabi\x15f\xfan\xf3fcGA(k\x1e\xb1\x14$\x10 6\xd5\x16\xe2\x10\x8b`68\xe3\xbcv\x8e\x83j\xab\x19F\x8f" 400 0 "-" "-"

Anyone has any idea what kind of exploit is tried here?

# Answer
You're looking at a hex-escaped string. After some googling, I found this entry on server-fault: https://serverfault.com/a/758511/90491.

You're looking at a non-decrypted HTTPS request.

**From Link:**

> You are most likely seeing this because you are making an HTTPS request to an HTTP endpoint. For example, you're sending an HTTPS request to port 80 of your web server instead of 443. As a result, the HTTP endpoint gets a bunch of encrypted data, makes no effort to decrypt it (since HTTP is supposed to be plaintext), and so you get a bunch of gibberish in the log file.
> 0 votes

---
Tags: security
---


# Question
Title: What are best practices for over-committing resources in a staging environment?
Suppose there is a staging environment very strapped for resources as new development, data workloads and other applications grow. Ideally one would like to maintain production parity, even at the resource allocation level per each deployed item in the staging environment. For example, one of the 12 Factor App principles describes this, taking great pains to emphasize not just a shallow kind of parity with mocking or lightweight spoofed resources, but rather *really* maintaining parity by running *the same* resources in staging.

Obviously for projects that scale up a lot, you may be budget constrained and simply have no choice but to spoof some resources in staging, use "sample" data or microservice stubs with the same shape as what real dependencies will look like in production, and other sacrifices.

But one type of sacrifice that is difficult to approach is reducing the basic allocated resources, like CPU, RAM, disk access, networking resources, logging, etc., so that a deployment in the staging environment becomes quite a different entity if you are interested in testing behavior of the whole stack of components together.

There are various tools that can help you automatically reduce resource usage, such as auto-scaling in many cloud vendor environment and in kubernetes, which in effect can lead to "overcommitting" your staging environment if deployments are asking for the same kinds of resources as in production but being tuned to use less as a function of real load or other dynamic conditions.

My question is: what is the state of best practices or understanding about this practice of overcommitting resources in staging. How often does this type of requirement become a necessity from budget and what are the major principles to think about when designing a solution in that case? What about the flip side of the issue: that "the cost of doing business" for a particular deployed entity should have the cost of significant production parity in staging impounded in as a basic need?

# Answer
> 1 votes
Very good question; I'm interested to see what comes up here.

In terms of cost, obviously each company and team is different. Ideally, everyone should be resource and cost conscious... but most people really don't seem to penny pinch by heavily monitoring and tuning their workloads (probably as that takes a certain skill level and tool set).

**My Thoughts / Habits:**

* Unlike **most** on-prem environments, it is very easy to spawn up dynamic environments in the cloud (if you're automating properly).
* So, when cost is prohibitive, you can just spin up full-scale staging environments in order to do load testing and then shut them down.
* This will work for **most** use cases. Obviously some things do only break when systems are alive a certain period of time under a certain load.
* We usually keep identical but smaller environments in staging. E.g. linearly scaled down presto clusters/spark clusters, k8s micro-services with less copies, and the like.
* We try to keep the actual memory/cpu requests (or config) the same on any tool. This allows for proper load testing without config changes for anything that scales.

**Additional Thought**

I'm pretty fond of the DevOps Toolkit book series by Victor Farcic. If you're using kubernetes, the 2.5 book (https://www.devopstoolkitseries.com/posts/devops-25/) goes into detail on using prometheus and alert manager to detect over-sized or undersized resource requests, among other things.

If you're really into saving resources and testing well simultaneously, it may make most sense to implement and use this in staging and prod. That way you can tune your alerting and automate your response so you can keep both environments sensibly sized for themselves in a consistent and enforced manner.

I think you'd still want to ensure you could set the staging environment (or another dynamic environment) to the prod settings to load test effectively though.

---
Tags: continuous-integration, deployment, continuous-deployment, autoscaling
---


# Question
Title: Jenkins pipeline fails on script approval, although it was approved
I have a pipeline which fails on script approval:

```
Scripts not permitted to use method org.jenkinsci.plugins.workflow.support.actions.EnvironmentAction getEnvironment. Administrators can decide whether to approve or reject this signature.
[Pipeline] End of Pipeline
[BFA] Scanning build for known causes...
[BFA] No failure causes found
[BFA] Done. 0s
[JobCompletedListener] Build result is: FAILURE
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use method org.jenkinsci.plugins.workflow.support.actions.EnvironmentAction getEnvironment

```

I went to in scriptApproval screen, approved the below:

```
signature: method org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper getRawBuild
signature: method java.net.URL getProtocol
signature: method java.lang.Throwable printStackTrace
signature: method org.jenkinsci.plugins.workflow.support.actions.EnvironmentAction getEnvironment

```

but on the next run I'm getting the exact same error, and approval request in scriptApproval screen, comes up again. any idea what is the root cause of this behavior? is there a workaround for it?

Jenkins is running as a container, and the Security plugin version is 1.60. BTW, the same job works perfect on other Jenkins which is VM

# Answer
The issue was with the wrong UID and GID of the user. after I've changed it from jenkins to 1000 1000 recursively, issue solved.
> 1 votes

---
Tags: jenkins-pipeline
---


title: Ansible Jinja template if statement

text:
# Question
Title: Ansible Jinja template if statement
This is a snippet from my Ansible jinja template which populates an environment specific template.

```
docker_compose_mq: <string-passed from Jenkins>
docker_compose_profiles: "string"

{% if "{{ risk_docker_compose_mq }}" == "string" %}
  {% "{{ risk_docker_compose_profiles: "string1" }}" %}
{% endif %}

```

This fails with a pretty generic error message:

```
"Syntax Error while loading YAML.\n\n\nThe error appears to have been in 'True': line 26, column 2, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\n(could not open file to display line)"}

```

I'm almost certain it's to do with escaping the quotes here but can't for the life of me work out what I'm doing wrong, any ideas?

# Answer
The syntax failures are caused by the presence of the `{{...}}` expression blocks (normally used for filling the template output with the corresponding content) inside the `{%...%}` statement blocks.

I only used standalone jinja2 templates, so I'm not 100% certain if this applies to Ansible jinja templates as well, but I suspect so. In the Jinja2 `{%...%}` statement blocks variables are referenced directly (and variable assignments are done in `{% set ...%}` statements), so what you're after may be along these lines:

```
{% set docker_compose_mq = <string-passed from Jenkins> %}
{% set docker_compose_profiles = "string" %}

{% if risk_docker_compose_mq == "string" %}
  {% set risk_docker_compose_profiles = "string1" %}
{% endif %}

```
> 3 votes

# Answer
The syntax is the below one:

```
{% if backup_dest[0:1]  == "/" %}

```

=\> this one tests if "backup\_dest" first character is "/"

```
{% if variable == "blabla" %}

```

=\> this one tests if "variable" equals to "blabla"

Regards
> 0 votes

---
Tags: ansible, jinja, templating
---


# Question
Title: error while loading shared libraries: libtinfo.so.6 : two behaviors for same docker image
I am developing an Erlang-OTP application, for that I use a docker image.

`docker-compose.yml`:

```
FROM centos
LABEL Name=myimage Version=2.0.0

RUN set -e \
   && yum -y install \
      autoconf \
      gcc \
      gcc-c++ \
      git \
      glibc-devel \
      make \
      ncurses-devel \
      tar \
      curl

ENV SSL_VERSION="1.0.2p"

RUN set -e \
   && mkdir -p /tmp/openssl \
   && cd /tmp \
   && curl -fSL -o openssl.sha256   http://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz.sha256 \
   && curl -fSL -o openssl.tar.gz http://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz \
   && SHA=$(printf "%s  openssl.tar.gz" `cat openssl.sha256` | sha256sum -c -); if [ "openssl.tar.gz: OK" != "${SHA}" ]; then exit 3; fi \
   && tar -zxf openssl.tar.gz -C /tmp/openssl --strip-components=1 \
   && cd /tmp/openssl \
   && ./Configure \
         --prefix=/usr/local/ssl \
         --openssldir=/usr/local/ssl \
      linux-x86_64 \
      shared \
   && make -j4 \
   && make install \
   && rm -Rf /tmp/openssl*

ENV OTP_VERSION="20.3.6"
ENV WITH_NATIVE=true

RUN set -e \
   && mkdir -p /tmp/otp_src \
   && cd /tmp \
   && curl --tlsv1.2 -fSL -o otp_src.tar.gz https://github.com/erlang/otp/archive/OTP-20.3.6.tar.gz \
   && tar -zxf otp_src.tar.gz -C /tmp/otp_src --strip-components=1 \
   && cd /tmp/otp_src \
   && ./otp_build autoconf \
   && ./configure \
         --prefix=/usr/local/otp \
         --enable-threads \
         --enable-smp-support \
         --enable-kernel-poll \
         --disable-dynamic-ssl-lib \
         --with-ssl=/usr/local/ssl \
         `test "${WITH_NATIVE}" = "true" && echo "--enable-hipe --enable-native-libs"` \
   && make -j4 \
   && make install \
   && ln -s /usr/local/otp_${OTP_VERSION} /usr/local/otp \
   && rm -Rf /tmp/otp_src*

ENV PATH $PATH:/usr/local/otp/bin

RUN set -e \
   && yum -y install \
      which

ENV REBAR3_VERSION="3.6.1"

RUN set -xe \
    && REBAR3_DOWNLOAD_URL="https://github.com/erlang/rebar3/archive/${REBAR3_VERSION}.tar.gz" \
    && REBAR3_DOWNLOAD_SHA256="40b3c85440f3235c7b149578d0211bdf57d1c66390f888bb771704f8abc71033" \
    && mkdir -p /usr/src/rebar3-src \
    && curl --tlsv1.2 -fSL -o rebar3-src.tar.gz "$REBAR3_DOWNLOAD_URL" \
    && echo "$REBAR3_DOWNLOAD_SHA256 rebar3-src.tar.gz" | sha256sum -c - \
    && tar -xzf rebar3-src.tar.gz -C /usr/src/rebar3-src --strip-components=1 \
    && rm rebar3-src.tar.gz \
    && cd /usr/src/rebar3-src \
    && HOME=$PWD ./bootstrap \
    && install -v ./rebar3 /usr/local/bin/ \
    && rm -rf /usr/src/rebar3-src

RUN mkdir /myimage
WORKDIR /myimage

```

Commands to run `docker-compose`

```
sudo docker-compose build
sudo docker-compose run --rm myimage bash

```

When I try to run production tar created by `Ubuntu-18.04`, I get:

> error while loading shared libraries: libtinfo.so.6: cannot open shared object file: No such file or directory.

I dont get any error while compiling. When I create this tar from `Debian-9`, it runs without error.

Debian machine has locally installed `erlang-otp`, but Ubuntu doesnt have.

# Answer
There is Docker's known issue #37531

To fix dependencies, you might try:

1. Either upgrade `Docker` to 17.02

```
curl -sSL https://get.docker.com/ | sudo bash

```
2. or install lib inside of container. Since your container based on Centos (`FROM centos`), so try `yum install`

```
rpm -ql libXtst-devel-1.2.2-2.1.el6.x86_64

```
> 1 votes

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


# Question
Title: Workflow with docker in the development environment
I have a couple of questions related to the usage of Docker in a development environment. I am going to propose three different scenarios of how I think Docker could be used in a development environment. Let's imagine that we are creating a REST API in Java and Spring Boot. For this, I will need a MySQL database.

1. The first scenario is to have a docker-compose for development with the MySQL container and a production docker-compose with MySQL and the Java application (jar) in another container. To develop I launch the docker-compose-dev.yml to start only the database. The application is launched and debugged using the IDE, for example, IntelliJ Idea. Any changes made to the code, the IDE will recognize and relaunch the application by applying the changes.
2. The second scenario is to have, for both the development and production environment, a docker-compose with the database and application containers. That way, every time I make a change in the code, I have to rebuild the image so that the changes are loaded in the image and the containers are launched again. This scenario may be the most typical and used for development with Docker, but it seems very slow due to the need to rebuild the image every time there is a change.
3. The third scenario consists of a mixture of the previous two. Two docker-compose. The development docker-compose contains both containers, but with mechanisms that allow a live reload of the application, mapping volumes and using, for example, Spring Dev Tools. In this way, the containers are launched and, in case of any change in the files, the application container will detect that there is a change and will be relaunched. For production, a docker-compose would be created simply with both containers, but without the functionality of live reload. This would be the ideal scenario, in my opinion, but I think it is very dependent on the technologies used since not all allow live reload.

The questions are as follows.

* Which of these scenarios is the most typical when using Docker for development?
* Is scenario 1 well raised? That is, dockerize only external services, such as databases, queues, etc. and perform the development and debugging of the application with the IDE without using Docker for it.

The doubts and the scenarios that I raise came up after I raised the problem that scenario 2 has. With each change in the code, having to rebuild the image and start the containers again is a significant waste of time. In short, a question would be: How to avoid this?

Thanks in advance for your time.

# Answer
> 1 votes
We use kubernetes / minikube rather than docker-compose, but its the same problem. We generally go with option #1 as:

* Development is 99% getting the app right.
* You want to be able to iterate fast/freely with your app.
* You want easy use of your debugger / IDE without inhibition.
* It lets you avoid configuring / managing remote debuggers from within the docker container.
    + If you did this in the container, you'd have to worry about making sure you didn't actually put it in prod as it can be harmful; see below.

For most code changes, we actually just have GitLab-CI set up so that it test-builds/deploys the container/app on check in (on their own branch/space). That way, most developers don't even need to think about the container part unless they're making mods to that area. But, obviously you'd still want them being able to run the MySQL container locally and easily.

### Remote Debugging Info

https://jaxenter.com/remote-debugging-java-applications-151466.html

> **Warning: Don’t keep remote debugging JVM arguments ON always, as it has following downsides:**
>
> Remote debugging mode disables several optimizations that JVM does to application to optimize the performance. All those optimizations will be lost. Remote debugging opens up a port. It’s a security risk, as anyone who can hit the server can initiate remote debugging

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


# Question
Title: Company is worried about exposing our PII to Tableau, Can we run Tableau without exposing our data to any 3rd parties?
I'm looking to understand a bit more from the technical side about how Tableau (The company itself) works with the data that everyone is providing them.

My company is looking to use Tableau as our main visualization tool as we grow larger, but we have a lot PII data, and just confidential data in general that we are not able to expose for compliance reasons to any 3rd parties.

Is there a way to run Tableau, and take advantage of all of the features that it has (Or a majority subset) in a way where we can still make connections to our reporting databases (MySQL/Postgres/RedShift), and also in such a way that a team of Data scientists can all access this information together, but silo it so that none of this information ever touches the Tableau company servers?

I know that most likely in good faith they do not store this information, but that is not enough for compliance reasons for us to work off of.

If I had an inherent mis understanding of the way in which Tableau operates I apologize, would love to learn more!

Thanks for the help

# Answer
There are several alternatives:
> 1 votes

---
Tags: security
---


# Question
Title: Multiple apps (microservices) and one proxy (nginx) docker-compose configuration/architecture
Having the following architecture:

* Microservice 1 + DB (microservice1/docker-compose.yml)
* Microservice 2 + DB (microservice2/docker-compose.yml)
* Proxy (proxy/docker-compose.yml)

Which of the following options would be the best to deploy in the production environment?

1. Docker Compose Overriding. Have a docker-compose for each microservice and another docker-compose for the proxy. When the production deployment is done, all the docker-compose would be merged to create only one (with `docker-compose -f microservice1/docker-compose.yml -f microservice2/docker-compose.yml -f proxy/docker-compose.yml up`. In this way, the proxy container, for example nginx, would have access to microservices to be able to redirect to one or the other depending on the request.
2. Shared external network. Have a docker-compose for each microservice and another docker-compose for the proxy. First, an external network would have to be created to link the proxy container with microservices.`docker network create nginx_network`. Then, in each docker-compose file, this network should be referenced in the necessary containers so that the proxy has visibility of the microservices and thus be able to use them in the configuration. An example is in the following link https://stackoverflow.com/a/48081535/6112286.

The first option is simple, but offers little felxibility when configuring many microservices or applications, since all docker-compose of all applications would need to be merged to generate the final configuration. The second option uses networks, which are a fundamental pillar of Docker. On the other hand, you don't need all docker-compose to be merged.

Of these two options, given the scenario of having several microservices and needing a single proxy to configure access, which would be the best? Why?

Tnahks in advance.

# Answer
> 4 votes
This is going to be an opinionated answer as both options are clearly possible.

I would go with the first option you described for the following reason:

It seems that at the moment you don't have a lot of microservices (otherwise you wouldn't be using docker-compose and would likely be doing k8s or at least docker swarm). Now, if your application grows a lot - you would likely outgrow compose in any case, so it would be wasteful if you optimize for compose at this stage anticipating future complexity.

So my take would be to go with option 1 for now which is much easier to implement. And when you need extra flexibility, likely you'd have other reasons to switch from docker-compose to something else.

---
Tags: docker, docker-compose, dockerfile
---


# Question
Title: Pometheus-operator - modify Grafana mixin dashboard
Whenever I try to edit the provisioned dashboards I get an error stating that the provisioned dashboard can't be edited. I saw that there is an option to allow changes from the UI, but my questions is if there is a way to modify it in an automatic/code way. I want to be able to add additions to the mixin without interacting with that repo but a clone of mine.

# Answer
You should use https://github.com/helm/charts/tree/master/stable/prometheus-operator helm chart , also you can write Grafana dashboard script that would create dashboard dynamically , can be update as well later on.
> 1 votes

---
Tags: prometheus, grafana
---


# Question
Title: Is Google Kubernetes (GKE) worth it for a program that runs once a week?
My team is on the process of migrating all our cloud applications from AWS to GCP, and we were considering using GKE for our main program, until we got the news that Google will now charge an hourly management fee of $0.10 for each cluster in GKE.

We still haven't started using GKE, and are now considering if it's really the best option for us. Our workload consists of two process-heavy data-analyses pipelines, which we use to run up to 20 analyses simultaneously in different AWS instances, running those once a week, for around 15min to 3h at most (and perhaps will start running it twice a week on the nearby future). On AWS, we currently spawn several instances of EC2 machines for each pipeline, one for each analyses, so we were considering GKE as we could run several analyses on the same cluster, and let GKE do the scaling for us.

I'm also under the impression that this cost is on top of the cost to have one pod running constantly for every nodepool, is that correct? For every nodepool we create inside our cluster, we'd have to pay for a pod to be running in there 24/7 as well, so that's another 'idle cost' to be considered...

We'd only need to run workloads on the cluster for around 15min to 6h each week, so paying for nodes to be up and running 24/7 seems a bit of a waste, but perhaps I'm not seeing the big picture here, as analyses could be run on the same cluster and save us money? Is there an efficient way to shut GKE down while we're not using it - either the pods or, better yet, the whole cluster itself? That'd save us at the very least 690h of running idle every month.

Would killing and deleting all our clusters as soon as the last analyses is done, and recreating it every week, once new analyses are needed, be something feasible? Would there be a cost involved with that? Is that feasible to be done 'automatically'?

# Answer
If your workloads are **exclusively** ephemeral, the answer is *probably not worth the infra management effort* of deploying K8S.

Kubernetes is best suited for types of workloads that are continuous, with regular incoming traffic and that require zero downtime. That's why it enables you to do things like rolling updates and implementing advanced traffic management patterns like Canary releases.

While you could have your cluster autoscale down to 0 worker nodes you would still incur in the cost of running the control plane node which requires running pods for the `apiserver`, the `controller-manager`, the `scheduler` and the `kube-proxy` in addition to running the `autoscaler` pods and log/metric collectors.

Deploying and destroying the clusters on demand is definitely feasible if you manage the cluster with Infrastructure as Code and design your pipelines so that they can setup and teardown clusters with minimal human intervention (waiting for apiserver to come up, waiting for workers to register and come up, etc). An even more elegant way of approaching it would be with using the Cluster API although this would require a management cluster.

Now, is it worth dealing with all the complexity inherent to K8S only to benefit from the downscaling and only to run occasional workloads? I'd say is probably best to manage your instances as regular autoscaling groups.
> 2 votes

---
Tags: kubernetes, google-cloud-platform, gcp
---


# Question
Title: What is the difference between a node and a machine on OpenShift?
OpenShift 4.2 documentation defines:

> **Machines**
>
> A fundamental unit that describes the host for a Node. A machine has a providerSpec, which describes the types of compute nodes that are offered for different cloud platforms. For example, a machine type for a worker node on Amazon Web Services (AWS) might define a specific machine type and required metadata.

https://docs.openshift.com/container-platform/4.1/machine\_management/creating-machineset.html

While Kubernetes doc defines:

> **Nodes**
>
> A node is a worker machine in Kubernetes, previously known as a minion. A node may be a VM or physical machine, depending on the cluster. Each node contains the services necessary to run pods and is managed by the master components. The services on a node include the container runtime, kubelet and kube-proxy. See The Kubernetes Node section in the architecture design doc for more details.

https://kubernetes.io/docs/concepts/architecture/nodes/

I don't know whether Kubernetes has the concept of *machines*, and I can't find on OpenShift's documentation its own definition of *node* (perhaps it uses Kubernetes'?)

And I can't get what's the difference between them. My current understanding is that a machine represents a raw physical or virtual machine; just the computational resources like cpu, memory and storage. Nodes, then, would represent a machine that is configured for using with OpenShift, that is, a machine that *contains the services necessary to run pods and is managed by the master components*.

Another theory would be that machines are just an abstraction to the existing infrastructure, so that persistent labels can be assigned to them for organizing the infrastructure, and as a way to provide information on the underlying infrastructure properties for the nodes.

So... What is really the difference between nodes and machines? Is a node in OpenShift exactly the same thing as in Kubernetes?

# Answer
Your interpretation is correct:

> My current understanding is that a machine represents a raw physical or virtual machine; just the computational resources like cpu, memory and storage. Nodes, then, would represent a machine that is configured for using with OpenShift, that is, a machine that contains the services necessary to run pods and is managed by the master components.

The differences arise on the level of abstraction.

* A Node in OpenShift is exactly the same thing as a Kubernetes node. It refers to the abstraction of a worker/master "Node" in a "Cluster". The Node abstraction only exists within the boundaries of a running cluster.
* A Machine is an abstraction introduced by the Cluster API which is an ongoing effort to allow deploying K8S clusters using a declarative approach. OpenShift is currently adopting the Cluster API hence they expect you to define the host infrastructure required to run your Nodes using the Machine spec.
> 3 votes

# Answer
Basically, a Node is just a simple worker OpenShift (or Kubernetes) instance where OpenShift can schedule Pods.

`Machine` is a new API introduce by OpenShift 4 that manage dynamic instance provisioning on top of public (AWS, Azure...) or private (OpenStack, VMWare...) cloud provider.
> 1 votes

---
Tags: kubernetes, openshift
---


# Question
Title: How can I get a list of encrypted disks for instances that are running on the AWS CLI?
There is a great question here about how to get a list of encrypted disks. I'm currently using the describe-volumes command.

For the record I'm currently using:

```
aws ec2 describe-volumes --region us-east-1 --filters Name=encrypted,Values=false Name=attachment.status,Values=attached --query "length(Volumes[])"

```

What I want is to filter that down further to just the instances that are running. (ie exclude the ones that are stopped).

My question is: **How can I get a list of encrypted disks for instances that are running on the AWS CLI?**

# Answer
> 2 votes
Here is what I ended up using. Enjoy.

```
for instance in $instances;
do
  count=`aws ec2 describe-volumes --filters Name=attachment.status,Values=attached Name=attachment.instance-id,Values=$instance --query "Volumes[]"  | jq  -r '. | length';`
  name=`aws ec2 describe-tags --filters Name=resource-id,Values=$instance Name=key,Values=Name --query Tags[].Value | jq -r '.[0]'`
  if [ $count -gt 0 ]; then
    START=0
    END=$count
    for ((i=START; i<END; i++))
    do
       #echo "i: $i"
       encrypted=`aws ec2 describe-volumes --filters Name=attachment.status,Values=attached Name=attachment.instance-id,Values=$instance --query "Volumes[]"  | jq  -r ".[$i].Encrypted";`
       volumeid=`aws ec2 describe-volumes --filters Name=attachment.status,Values=attached Name=attachment.instance-id,Values=$instance --query "Volumes[]"  | jq  -r ".[$i].VolumeId";`
       echo "$instance $name Volumes: $count VolumeId: $volumeid Encrypted: $encrypted "
    done
  fi
done

```

# Answer
> 1 votes
I'm not sure if you can do this without a loop. But you should be able to run the below in bash and get the right output:

```
instances=`aws ec2 describe-instances --region us-east-1 --filters Name=instance-state-name,Values=running --query "Reservations[*].Instances[0].InstanceId" --output text`

for instance in $instances;
do
   aws ec2 describe-volumes --region us-east-1 --filters Name=encrypted,Values=true Name=attachment.status,Values=attached Name=attachment.instance-id,Values=$instance --query "Volumes[]";
done

```

This will return all information on the volumes. For the ID you can change the `describe-volumes` line to:

```
aws ec2 describe-volumes --filters Name=encrypted,Values=false Name=attachment.status,Values=attached Name=attachment.instance-id,Values=$instance --query "Volumes[].Attachments[].VolumeId"

```

# Answer
> 0 votes
Below presented there are is a Bash script functions based on `awscli` to get **AWS EBS volumes encryption state** for different scenarios

**NOTE1:** your IAM Profile and that is currently running

source public github gist: https://gist.github.com/exequielrafaela/4cce5cf7198d5f239153e339587ab392

**NOTE2:** You'll find other bash scripts for some usual Sec & Audit validations.

```
#!/bin/bash

#
# Bash script functions based on awscli to get AWS EBS volumes encryption state for different scenarios
# your IAM Profile and that is currently running
#

#
# Your AWS IAM profile here (~/.aws/credentials & ~/.aws/config).
#
AWS_IAM_PROFILE="your-aws-iam-profile-here"

#
# AWS EBS status -> attached || deattached
#
AWS_EBS_ATTACHMENT_STATUS="attached"

#=========================================#
# Functions                               #
#=========================================#
func_aws_ec2_ebs_list_encrypted(){
    #
    # Get all running AWS EC2 accessible via your ${AWS_IAM_PROFILE} role.
    #
    instances=`aws ec2 describe-instances --region us-east-1 \
    --filters Name=instance-state-name,Values=running \
    --query "Reservations[*].Instances[0].InstanceId" \
    --output text \
    --profile ${AWS_IAM_PROFILE}`

    #
    # Iterate over the Instances list and present:
    # echo "${instance} $name Volumes: $count VolumeId: $volumeid Encrypted: $encrypted"
    # eg: i-111111111111111 Jenkins Volumes: 2 VolumeId: vol-111111111111111 Encrypted: false
    #
    echo "#===============================================#"
    echo "# EBS Volumes attached to running EC2 Instances #"
    echo "#===============================================#"
    for instance in ${instances};
    do
      count=`aws ec2 describe-volumes --profile ${AWS_IAM_PROFILE} \
      --filters Name=attachment.status,Values=${AWS_EBS_ATTACHMENT_STATUS} Name=attachment.instance-id,Values=${instance} \
      --query "Volumes[]"  | jq  -r '. | length';`

      name=`aws ec2 describe-tags --profile ${AWS_IAM_PROFILE} \
      --filters Name=resource-id,Values=${instance} Name=key,Values=Name \
      --query Tags[].Value | jq -r '.[0]'`

      if [[ ${count} -gt 0 ]]; then
        START=0
        END=${count}
        for ((i=START; i<END; i++))
        do
           #echo "i: $i"
           encrypted=`aws ec2 describe-volumes --profile ${AWS_IAM_PROFILE} \
           --filters Name=attachment.status,Values=${AWS_EBS_ATTACHMENT_STATUS} Name=attachment.instance-id,Values=${instance} \
           --query "Volumes[]"  | jq  -r ".[$i].Encrypted";`

           volumeid=`aws ec2 describe-volumes --profile ${AWS_IAM_PROFILE} \
           --filters Name=attachment.status,Values=${AWS_EBS_ATTACHMENT_STATUS} Name=attachment.instance-id,Values=${instance} \
           --query "Volumes[]"  | jq  -r ".[$i].VolumeId";`

           echo "EC2: ${instance} $name Volumes: $count EbsVolumeId: $volumeid Encrypted: $encrypted "
        done
      fi
    done
}

func_aws_ebs_list_encrypted(){
    echo ""
    echo "#==============================================#"
    echo "# All EBS Volumes                              #"
    echo "#==============================================#"
    ebs_count=`aws ec2 describe-volumes --profile ${AWS_IAM_PROFILE} \
    --query "Volumes[]"  | jq ".[].VolumeId | length" | wc -l`

    echo "N° AWS EBS VOLUMES: ${ebs_count}"
    echo ""

    if [[ ${ebs_count} -gt 0 ]]; then
    START=0
    END=${ebs_count}
    for ((i=START; i<END; i++))
    do
       #echo "i: $i"
        ebs_volumeid=`aws ec2 describe-volumes --profile ${AWS_IAM_PROFILE} \
        --query "Volumes[]"  | jq -r ".[$i].VolumeId"`

        ebs_encrypted=`aws ec2 describe-volumes --profile ${AWS_IAM_PROFILE} \
        --query "Volumes[]"  | jq -r ".[$i].Encrypted"`

       echo "EbsVolumeId: ${ebs_volumeid} Encrypted: ${ebs_encrypted}"
    done
    fi
}

#=========================================#
# Main() - Function calls                 #
#=========================================#
func_aws_ec2_ebs_list_encrypted
func_aws_ebs_list_encrypted

```

# Answer
> 0 votes
This can be done using the AWS CLI:

```
aws ec2 describe-volumes --query Volumes[*].VolumeId --filters Name=encrypted,Values=true

```

---
Tags: amazon-ec2, encryption, aws-cli
---


# Question
Title: How do fail a Packer pipeline upon powershell provisioner pester test failure?
I'm building a packer pipeline and having an issue in getting the failure of a powershell provisioner step to fail the packer job itself. This is important as without failing the Packer job, the AMI would be published, despite the test failure.

How I'm proceeding:

1. Run provisioning setup steps
2. Copy Pester Script to Remote machine
3. Invoke inline powershell statement to `Invoke-Pester`
4. Download the test results from the Pester remote run
5. Next provisioning step parses the file to count errors and throws error upon issue count \> 0

However, even with issue count being \> 0 it is not causing the pipeline to fail. Additionally some errors thrown in other provisioner steps also fail to cause the Packer job to stop. I've set `$ErrorActionPreference = 'Stop'` on one of them and it didn't seem to make any difference.

Here's part of the provisioning workflow for packer.

```
...     {
            "type": "file",
            "source": "{{ template_dir }}/tests/windows-server.tests.ps1",
            "destination": "{{ user `TEMP_DIRECTORY` }}/"
        },
        {
            "type": "powershell",
            "environment_vars": [
                "TEMP_DIRECTORY={{ user `TEMP_DIRECTORY` }}/"
            ],
            "inline": [
                "if(-not (Get-InstalledModule Pester -MinimumVersion 4.10.1)){ Install-Module Pester -Scope AllUsers -AllowClobber -Force -verbose} ",
                "Import-Module Pester -MinimumVersion 4.10.1 -Force -DisableNameChecking",
                "$null = New-Item -Path $ENV:TEMP_DIRECTORY -ItemType Directory -Force -ErrorAction SilentlyContinue",
                "$testresult = Invoke-Pester -Script (Join-Path $ENV:TEMP_DIRECTORY 'windows-server.tests.ps1') -OutputFile (Join-Path $ENV:TEMP_DIRECTORY 'TEST-pester-results.xml') -OutputFormat 'NUnitXML' -PassThru"
            ]
        },
        {
            "type": "file",
            "direction": "download",
            "source": "{{ user `TEMP_DIRECTORY` }}/TEST-pester-results.xml",
            "destination": "{{ template_dir }}/artifacts/TEST-pester-results.xml"
        }, ...

```

Once this part is done it's followed by this step which is some logic from this blog post:

```
  {
            "environment_vars": [
                "TEMP_DIRECTORY={{ user `TEMP_DIRECTORY` }}/"
            ],
            "script": "./scripts/Get-TestResults.ps1",
            "type": "powershell"
        },

```

The `Get-TestResults.ps1` has the following function thanks to this article: Testing Packer Images with Pester written originally by Sam Cogan and modified slightly by me.

```
[cmdletbinding()]
param()
$TestFile = Join-Path $ENV:TEMP_DIRECTORY 'TEST-pester-results.xml'

if (Test-Path -Path $TestFile -PathType Leaf)
{
    [xml]$testResults = Get-Content -Path $TestFile -Raw
    $totalIssues=[int]$($testResults.'test-results'.errors) + [int]$($testResults.'test-results'.failures) + [int]$($testResults.'test-results'.invalid)
    exit $totalIssues
}
else
{
    Write-Error " Failed to find `$TestFile: $TestFile"
    Write-Warning "$(Get-ChildItem $ENV:TEMP_DIRECTORY -Recurse | Format-Table -autosize -wrap | Out-String)"
    Write-Error " Failed to find `$TestFile: $TestFile"
    exit 1  #not a good exit :-)

}

```

# Answer
After resolving some syntax issues, I found the true cause of failing to throw the error. In my prior usage I was doing this through Inspec provisioner, which handled the exit codes.

If you are using Pester and having to do the workaround I described above, then to ensure error's in a step are thrown you need to throw an exit code other than 0.

The two steps I took that seem to work fine (I like some emoji fire in my logs )

```
$ErrorActionPreference = 'Stop'

try
{
# Do code here
}
catch
{
   Write-Error " Failed to do something important `$TestFile: $TestFile"
  exit 1  # packer will recognize failure at this point
}

```

Note that you will want to make sure your Azure DevOps Pipeline has the following settings to publish test results regardless of failing:

```
# ℹ  Using Invoke-Build to call Packer. You can do this with a packer extension or any other way you prefer
- task: PowerShell@2
  displayName: Run Packer Configuration
  inputs:
      filePath: build/build.ps1
      arguments: '-Task PackerBuild -Configuration $(Configuration)'
      errorActionPreference: 'Continue'
      pwsh: true
  continueOnError: true #I want to publish the test results regardless

- task: PublishTestResults@2
  displayName: Publish Pester Tests
  inputs:
      testResultsFormat: 'NUnit'
      testResultsFiles: '**/TEST-*.xml'
  condition: succeededOrFailed()

```
> 4 votes

---
Tags: azure-devops, packer
---


# Question
Title: Is there any way to break long command into multi lines in GitlabCI
I have a very long command in `.gitlab-ci.yml` file to ssh to jump host then use `rsync` to sync files from my repo to destination host (it does not have public ip so I need to access it via jump host).

Here is my `.gitlab-ci`:

```
image: ubuntu
before_script:
  - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client rsync git -y )'
  - mkdir -p ~/.ssh
  - chmod 700 ~/.ssh
  - echo -e "$PRIVATE_KEY" > ~/.ssh/id_rsa
  - chmod 600 ~/.ssh/id_rsa
  - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

SSH:
  tags:
    - mytag
  script:
  - ssh ubuntu@host "which ssh-agent || ( apt-get update -y && apt-get install openssh-client rsync git -y ) && ssh ubuntu@192.168.1.2 "mkdir -p /home/ubuntu/test" && rsync /home/ubuntu/test/.gitlab-ci.yml ubuntu@192.168.1.2:/home/ubuntu/test/.gitlab-ci.yml"

```

The command here is so long:

```
 ssh ubuntu@host "which ssh-agent || ( apt-get update -y && apt-get install openssh-client rsync git -y ) && ssh ubuntu@192.168.1.2 "mkdir -p /home/ubuntu/test" && rsync /home/ubuntu/test/.gitlab-ci.yml ubuntu@192.168.1.2:/home/ubuntu/test/.gitlab-ci.yml"

```

Let me explain it:

* First it `ssh` to `host` then install `rsync` if it does not exist, then it ssh to my private server `192.168.1.2` and then sync my file named `.gitlab-ci.yml` (the file from my repo in my Gitlab server) to folder `test`

I just wonder if there is any way to break long command above to multi lines command?

# Answer
Since `.gitlab-ci.yml` is a `Yaml` file, then just use it's syntax.

For example, you may use `>`:

```
image: ubuntu
before_script:
  - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client rsync git -y )'
  - mkdir -p ~/.ssh
  - chmod 700 ~/.ssh
  - echo -e "$PRIVATE_KEY" > ~/.ssh/id_rsa
  - chmod 600 ~/.ssh/id_rsa
  - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

SSH:
  tags:
    - mytag
  script: >
  - ssh ubuntu@host "which ssh-agent ||
    ( apt-get update -y && apt-get install openssh-client rsync git -y ) &&
    ssh ubuntu@192.168.1.2 "mkdir -p /home/ubuntu/test" &&
    rsync /home/ubuntu/test/.gitlab-ci.yml ubuntu@192.168.1.2:/home/ubuntu/test/.gitlab-ci.yml"

```

# Sample usage of `yaml` multilines

There is a great resource about `yaml` multilines: YAML Multiline Strings Also, there is a great SO answer about `yaml` multilines.

So let's speculate about pipeline based on these materials. Since we have specific context (script for `Gitlab CI`) then we don't need all of theese 63 cases:

```
                      >     |            "     '     >-     >+     |-     |+
-------------------------|------|-----|-----|-----|------|------|------|------
Trailing spaces   | Kept | Kept |     |     |     | Kept | Kept | Kept | Kept
Single newline => | _    | \n   | _   | _   | _   | _    |  _   | \n   | \n
Double newline => | \n   | \n\n | \n  | \n  | \n  | \n   |  \n  | \n\n | \n\n
Final newline  => | \n   | \n   |     |     |     |      |  \n  |      | \n
Final dbl nl's => |      |      |     |     |     |      | Kept |      | Kept
In-line newlines  | No   | No   | No  | \n  | No  | No   | No   | No   | No
Spaceless newlines| No   | No   | No  | \   | No  | No   | No   | No   | No
Single quote      | '    | '    | '   | '   | ''  | '    | '    | '    | '
Double quote      | "    | "    | "   | \"  | "   | "    | "    | "    | "
Backslash         | \    | \    | \   | \\  | \   | \    | \    | \    | \
" #", ": "        | Ok   | Ok   | No  | Ok  | Ok  | Ok   | Ok   | Ok   | Ok
Can start on same | No   | No   | Yes | Yes | Yes | No   | No   | No   | No
line as key       |

```

Assumptions are:

* we don't need trailing spaces at all
* we don't need final newlines at all
* we'll try to avoid quote escaping mess
* Backslash is intended to combine multi-line scripts
* almost doesn't matter how many spaces before the script

P.s. I'd suggest to lint your `.gitlab-ci.yml` using GitLab UI: Validate GitLab CI/CD configuration
> 12 votes

---
Tags: gitlab
---


title: Can't ping client on ansible ,

text:
# Question
Title: Can't ping client on ansible ,
```
$ ansible 192.168.254.150 -m ping

[WARNING]: Unable to parse /etc/ansible/hosts enable callback plugins as an
inventory source
[WARNING]: Unable to parse /etc/ansible/they can output to stdout but cannot be
'stdout' type. callback_whitelist = timer as an inventory source
[WARNING]: Unable to parse /etc/ansible/mail as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: 192.168.254.150

```

# Answer
> 3 votes
Try this, to run an adhoc command with IP address

```
ansible all -i 192.168.254.150, -m ping
192.168.254.150 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

```

From man:

> -i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY specify inventory host path or **comma separated host**

---
Tags: ansible, ubuntu
---


# Question
Title: Best practise/standard practise for semantic versioning in development
I have a project that looks like this:

```
SOME_MONOREPO, managed by lerna

- package-a
- package-b - depends on package-a, package-c
- package-c - is currently private, so not published as npm package.
When package-b builds, it accesses package-c directly via symlink.
As we move forward, we'll transition this to published packages like package-a.

ANOTHER_PROJECT

- package-foo- depends on SOME_MONOREPO.package-a

```

Now, say I'm doing some work on package-a, this could be a major, minor or patch change.

There are a few possible development flows:

* The simplest: the work just occurs on package-a, I write tests for it, and then when ready version bump and push to master.
* I'm doing work on package-a, but also updating package-b to adapt to the breaking changes/use the new functionality. In this scenario version bump isn't strictly necessary to do the code, because lerna's symlinks will still let package-b access the package-a code.
* I'm also doing work on package-foo. In this case I need to be publishing to npm in order to access the code.

So, I'm thinking that nightly/unstable/prerelease builds are warranted here. That is - I build some functionality on package-a, build an unstable artefact, and then package-foo can use it, see if it's fit for purpose.

At some point though - a decision needs to be made whether this is a major, minor or patch update.

The question is - when should this happen? Does the developer, when making changes, decide on their first PR to develop each time what the version bump is? (And it not being a release PR, the CI automatically publishes it with the 'unstable' appendix, when it is release the unstable appendix is removed). What about if another developer is simultaneously working on the same package?

Is there a way to not think about version bumps until formal release?

# Answer
> 2 votes
Version bumps should happen every single build. Waiting until a formal release and releasing everything as 1.0.0 is an option, but you should still know what build you are using in your alpha/beta.

Ultimately, the developer will have to determine if a major release increment is needed. You should only do a major release bump if you introduced a breaking change.

For your regular builds, a common practice is to let your CI tool increment the "patch release" number or the X.X.**Patch** portion of the version. This way your versioning is tied to your builds which will help the development and testing process. If you choose to only do a nightly build, you can have your CI tool increment this number then so that you and other developers know what version of the package they are using.

NPM has published a good guide on how to handle semantic versioning.

---
Tags: versioning, npm
---


title: Where to put ansible-vault password

text:
# Question
Title: Where to put ansible-vault password
We are planning to use ansible vault in our project to prevent leaking passwords or keys in git.

The idea is to put all our sensitive data into a plain file then encrypt this file with ansible-vault using a password before pushing to git.

To decrypt the file, we have to pass the vault password to ansible, I'm thinking about 3 possibilities:

* Store it inside a server environnment variable
* Pass it as an option to ansible-playbook command
* Store it into a non versionned file.

Is there any other options, which is the best (and secure) way to store ansible-vault password , ansible best practices documentation is not saying anything on this.

# Answer
> The idea is to put all our sensitive data \[...\]

The meaning of "all" in this sentence should be analyzed very carefully before implementing the solution that you plan.

Ansible vault is a very useful tool, but it should be used only to store secrets that are:

1. Specifically needed for the ansible deployments
2. Easily made useless to owners that should become unaware of them, but that may illegitimately "remember" them (typically off-boarded employees)

The second point is critical.

Many people, and potentially the whole DevOps team, will have access to the ansible vault password and therefore all the secrets.

Therefore, for all the secrets stored in the vault, a condition should hold for which a person or machine with **unauthorized** access to them should be incapable of making any use of them if so is desired.

In concrete terms, if you use ansible to deploy a database and its users, you can store the passwords in the vault, but you will have to be very careful (and most likely consider another solution) if that service will be available from the Internet and without the need for any VPN authentication!

Users (DevOps) exposed to the secret, should be incapable of using "remembered" passwords if one security barrier is imposed on them (e.g., VPN access revoked). In addition to this, access to the source code repository (where the vault is stored) should be revoked as well before passwords are changed.

Under these conditions, ansible vault is a very useful tool.

Trying to store a secret that could be used by any person or machine on the Internet in the vault would be instead a mistake (e.g., VPN credentials of users).

> Is there any other options, which is the best (and secure) way to store ansible-vault password

Under the conditions from the previous paragraph, I think that a good practice would be:

1. Store the vault password in an external secure vault (something like Vault from HashiCorp or any SaaS for credentials management)
2. Allow access to the external vault item to DevOps (they will need the password for testing) and the CI/CD system or ansible controller
3. Keep a **convention to use secrets**! You will not be able to review changes to the secrets and you will not be able to grep for ansible variables in secrets files! So be thorough since the beginning. A good convention is to name all variables stored in the ansible vault with a `secret_` prefix. When you will see something like:

postgres.yml:

```
postgres_password: "{{ secret_postgres_password }}"

```

you will know that the value is stored in the ansible vault.
> 15 votes

# Answer
> We are planning to use ansible vault in our project to prevent leaking passwords or keys in git.

Since you haven't yet implemented anything, you might reconsider this. Using a system like Ansible vault has a number of security downsides:

* there is no audit trail of who has accessed it
* when an employee leaves, it is easy for them to take the secret store with them
* when an employee leaves, removing their access means changing the password and redistributing it to everyone else
* a compromised Ansible vault password can be forever used on an old version of the vault, as stored in version control
* secrets have to be static

A potentially much more secure, albeit more complex, system that does not have these downsides is to use Hashicorp Vault to store your secrets. You can then still pull values from it almost as easily as from Ansible vault by using https://github.com/jhaals/ansible-vault .

You then have to manage authentication to Hashicorp Vault, though, and that is the turtle question. For humans, I think the best solution is to prompt for a password periodically and expire the token after a short amount of time; for machines, to use the AWS authentication backend or similar. You can never entirely get rid of the need for authentication somewhere, but you can make it harder for an attacker to gain access to it.

Now, if setting up and administering a secrets server is too much for you, then certainly you can just use Ansible vault. Why store the password at all on the individual machines though? For interactive use, you can just prompt for the password, and users can store it in their password manager of choice. iTerm on OS X has a password manager that integrates with Keychain.app that makes this particularly easy there.
> 10 votes

# Answer
This quite much goes to what internal policies you have on handling sensitive data.

I'd like to tell you my approach to this and explain what I see as pros and cons. I keep the Ansible Vault password in a file on the control machine and have a environment variable pointing to it:

```
export ANSIBLE_VAULT_PASSWORD_FILE=/deep/dark/place

```

I have that on my workstation (as I need to test & develop playbooks), some colleagues have it as well, and of course we have it on the main Ansible control machine.

Pros:

* not in a shared location/repository (it's a non versioned file as you say)
* one does not need to know your Ansible vault password to run a play (this is under the condition that you have a CI tool, e.g. Jenkins, where you can easily launch playbooks)

Cons:

* not easy to rotate the password
* everyone who works on your playbooks needs to have it on his workstation

The cons do have mitigations, but again it's up to the policies and rules you have adopted in you day to day operations.
> 5 votes

# Answer
I store them in my terminal session using `keyctl`. When I open a terminal session, I input my passwords once.

`keyctl` allows you to store passwords at different levels, I have chosen session level but you can store it at user or host level.

To perform that, define property `vault_identity_list` in file *ansible.cfg* :

```
vault_identity_list = my_key@./scripts/my_key.py

```

Create a python script named *my\_key.py* in directory *./scripts* with this content :

```
#!/usr/bin/python
# coding: utf8

import subprocess
import sys
import getpass

key_name = "my_key"
try:
  keyid = int(subprocess.Popen("keyctl request user {} @s".format(key_name), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read())
  print subprocess.Popen("keyctl print {}".format(str(keyid)), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read().rstrip()
except ValueError:
  sys.stderr.write("Password for '{}' : ".format(key_name))
  password = getpass.getpass("").rstrip()
  subprocess.Popen("keyctl add user {} '{}' @s".format(key_name, password), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  print password

```

Now, when you type `ansible-playbook -e @my_vault.vault ...`, it asks you password only once per sessions.

Whith this approach, you can use easily several vaults (each of them with a python script, I don't find a way to use the same script with all vaults).
> 2 votes

# Answer
Take a look on this project to manage your ansible vault encrypting passwords https://github.com/Smile-SA/ansible-vault-manager

It handle multiple keyring storage platforms with plugins (for now only AWS SSM implemented). Morehover integration with a current Ansible project is very easy...
> 1 votes

---
Tags: ansible, git, security, practices, ansible-vault
---


title: Can't write to Docker volume

text:
# Question
Title: Can't write to Docker volume
### My set-up

* I have a Docker image based on `php:7.4-apache`.
* I have two Docker volumes for saving files that need to be persisted.
* On container start, I run Certbot to install HTTPs certificates.

### Issue

I discovered that **my application can't write to Docker volumes**.

### Debugging

Using `ls -l` I found out that the mountpoints of my volumes are owned by user `1451`:

```
drwxr-xr-x 4     1451 users     176128 Mar 12 13:25 volume_mountpoint

```

My web server is running under user `www-data`.

### Attempted solution

I've tried setting the user under which my container runs to `www-data`. This caused the volume mountpoints to be owned by `www-data`, which fixed the permissions issue. The problem with this solution is that `Certbot` requires `root` permissions and fails to acquire HTTPs certificate without it.

### Question

What is the proper way to fix this issue? I need `Certbot` to run under root, but let mountpoints to be owned by `www-data`.

# Answer
> 1 votes
Solution that worked for me in the past: create a new image out of the existing one and let entrypoint script of that new image to modify permissions of your volume\_mountpoint.

So in the case of your image (php:7.4-apache) you create entrypoint.sh file, something like

```
chown www-data:www-data -R /path/to/volume_mountpoint
apache2-foreground

```

And then your Dockerfile should be something like

```
FROM php:7.4-apache
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

```

This way it should correct the permissions when container starts. Note, that I haven't tested the above, might require some tweaks - but hopefully it shows the idea.

P.s. Maybe somebody has a better way of doing this - I would be very interested myself.

---
Tags: docker
---


# Question
Title: How to convert a docker-compose file to kubernetes file(s)?
Is there any easy way to convert a docker-compose.yml file to Kubernetes file(s)?

# Answer
The original and most popular solution I've seen is kompose which does exactly as you are asking, converts the compose yaml file into kubernetes yaml files.

If you want to continue working with a compose.yml file for compatibility with other systems, then docker recently open sourced their compose on kubernetes solution that integrates directly into kubernetes.
> 4 votes

# Answer
This online tool will translate your compose file equivalent Kubernetes resources
> 0 votes

---
Tags: docker, kubernetes, docker-compose
---


# Question
Title: What are reasons to prefer an ingress over using `expose` in k8s?
If one uses `expose` in k8s then it is possible to assign an IP to an app so it could be accessed on the www.

It is also possible to configure an ingress. This is basically a rproxy.

What are reasons to use an ingress over `expose`?

# Answer
> 2 votes
As @Tensibai indicated:

> With an ingress you can have multiples names on same port, no possible by exposing a port tied to only one service

# Answer
> 0 votes
From a technical perspective, they are working in different tcp/ip layers.

Expose command create a layer 4 tcp/udp port redirection. While ingress works at layer 7, ingress can do alot more like ssl offlloading, distribute loads based on HTTP headers, cookies, or url etc

---
Tags: kubernetes
---