# Question
Title: how to create dynamic stages in jenkins pipeline
I want to use a python script as input to create stages in jenkins pipeline

test.py

```
{'job-name': 'Test1', 'action': 'a', 'targetname': 'x'}
{'job-name': 'Test2', 'action': 'b', 'targetname': 'y'}
{'job-name': 'Test3', 'action': 'c', 'targetname': 'z'}

```

The output of the above python script is a dictionary.

How to run this python script in Jenkins pipeline in a stage and how to store the output and use the output to define further stages

Example:

```
stage(Test1) {

}
stage(Test2) {

}
stage(Test3) {

}

```

Extract only 'value' of a particular 'key' from the output of python script to define stages in Jenkins pipeline.

How to execute it in Jenkins groovy as declarative pipeline ?

# Answer
> 1 votes
This was already asked and answered over on StackOverflow.

TL;DR: you must use Scripted Pipeline; Declarative does not support dynamic stages. Here is a copy-paste of the top answer:

> Use the scripted syntax that allows more flexibility than the declarative syntax, even though the declarative is more documented and recommended.
>
> For example stages can be created in a loop:
>
> ```
> def tests = params.Tests.split(',')
> for (int i = 0; i < tests.length; i++) {
>     stage("Test ${tests[i]}") {
>         sh '....'
>     }
> }
>
> ```

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


# Question
Title: How do I troubleshoot a dateparsefailure when using Logstash's date plugin?
I'm getting a date parse failure when trying to parse a log that has the following format:

```
172.20.21.10 - - [29/Mar/2022:12:41:27 -0400] "some invalid request" 400 226

```

The event structure looks like this:

```
{
        "request" => "/um/",
           "auth" => "-",
          "ident" => "-",
      "@metadata" => {
        "path" => "C:/net-logs/m4-httpd-logs/wordpress_access.log-20220403",
        "host" => "M6"
    },
           "verb" => "GET",
        "message" => "172.20.21.10 - - [29/Mar/2022:12:44:36 -0400] \"GET /um/ HTTP/1.1\" 404 17787",
           "path" => "C:/net-logs/m4-httpd-logs/wordpress_access.log-20220403",
          "bytes" => "17787",
       "response" => "404",
       "clientip" => "172.20.21.10",
       "@version" => "1",
           "host" => "M6",
    "httpversion" => "1.1",
      "timestamp" => "29/Mar/2022:12:44:36 -0400"
}

```

To convert the timestamp field from text to a date I have a filter in the logstash configuration file that looks like this:

```
filter {
        grok {
              match => {"message" => "%{COMMONAPACHELOG}"}
        }
        mutate {
                remove_field => [ "@timestamp"]
        }
        date {
              match => ["timestamp", "dd/MM/yyyy:HH:mm:ss Z"]
              target => ["timestamp"]
        }
}

```

I have used the correct syntax for the format according to the documentation for the date filter. I'm not sure whats causing the parse failure since the error msg does not show exactly why the parse failed. It looks like this:

```
{
        "request" => "/wp-includes/IXR/login",
           "auth" => "-",
          "ident" => "-",
      "@metadata" => {
        "path" => "C:/net-logs/m4-httpd-logs/wordpress_access.log-20220403",
        "host" => "M6"
    },
           "verb" => "GET",
        "message" => "172.20.21.10 - - [29/Mar/2022:12:47:57 -0400] \"GET /wp-includes/IXR/login HTTP/1.1\" 404 17787",
           "tags" => [
        [0] "_dateparsefailure"
    ],
           "path" => "C:/net-logs/m4-httpd-logs/wordpress_access.log-20220403",
       "response" => "404",
          "bytes" => "17787",
       "clientip" => "172.20.21.10",
       "@version" => "1",
           "host" => "M6",
    "httpversion" => "1.1",
      "timestamp" => "29/Mar/2022:12:47:57 -0400"
}

```

# Answer
Fixed by creating a mapping for the timestamp field:

```
{
  "index_patterns": "httpd-*",
  "mappings": {
    "dynamic": true,
    "properties": {
        "request": {
          "type": "text"
        },
        "auth": {
          "type": "text"
        },
        "ident": {
          "type": "text"
        },
        "verb": {
          "type": "text"
        },
        "response": {
          "type": "text"
        },
        "bytes": {
          "type": "integer"
        },
        "clientip": {
          "type": "ip"
        },
        "httpversion": {
          "type": "text"
        },
        "timestamp": {
          "type": "date",
          "format": "dd/MMM/yyyy:HH:mm:ss Z"
        }
    }
  }

```
> 0 votes

---
Tags: logstash
---


title: Why pods are started for old ReplicaSet

text:
# Question
Title: Why pods are started for old ReplicaSet
A new deployment has been created and the release was successfully deployed on our AKS cluster.

We have noticed in logs that pods, for old ReplicaSet(which still exists on the cluster), are regularly executed. This is actually happening only for one specific ReplicaSet. The reason we have noticed it - it tries to perform a database update for an old db version.

Any idea why this may happen?

UPDATE: it turned out that we run "old" pod on a system test cluster (unfortunately connection string was set incorrectly :( ). The misleading thing was that ReplicaSet have the same name... because

```
Notice that the name of the ReplicaSet is always
formatted as [DEPLOYMENT-NAME]-[RANDOM-STRING].
The random string is randomly generated and uses the
pod-template-hash as a seed.

```

# Answer
> 0 votes
I need to clear some stuff please :

1- Do you create a totally new Deployment ?

**Ex:**

The old deployment has name **Deployment\_1**

The new deployment has name **Deployment\_2**

2- If yes. Do you created a totally new deployment just because the old one is not updating the pods for the blocker that you mentioned above ?

3- If yes and you update the image name for that deployment. then you need set the replicas to zero using this command.

```
kubectl -n NAMESPACE scale deploy DEPLOYMENT_NAME --replicas=0

```

And make sure that the replicas is zero by this command.

```
kubectl -n NAMESPACE get deploy/DEPLOYMENT_NAME

```

Then scale it up again.

```
kubectl -n NAMESPACE scale deploy DEPLOYMENT_NAME --replicas=1

```

Note: You can set the count of replicas that you need I just write 1 for example.

---
Tags: kubernetes
---


# Question
Title: Kubernetes container networking between pods
So I have a few services running using nodejs, in more than one kubernetes pod.

These services obviously need to talk to each other, and be able to find the database included in this kubernetes cluster.

In docker-compose I could just use the container name and it would automatically route me to the correct one, with kubernetes it does not seem to be the case.

How do I route to specific containers in different pods in Kubernetes? I tried service names, using the namespace set up by the pipeline's admin team (`<POD>`.`<NAMESPACE>`.svc.cluster.local), and an ExternalName, but every time I get the same error: `Error: getaddrinfo ENOTFOUND`

Any advice would be appreciated as I am new to kubernetes.

# Answer
> 4 votes
Normally, you access services using the name provided by a `Service` resource.

For example, if I have a `Pod` running Redis, like this:

```
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: redis
  name: redis
spec:
  containers:
    - image: docker.io/redis:latest
      name: redis
      ports:
      - containerPort: 6379
        name: redis

```

I might have a service definition that looks like:

```
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  selector:
    app: redis
  ports:
  - port: 6379
    targetPort: redis

```

With these in place, from another `Pod` I can refer to the Redis service using the hostname `redis`:

```
[root@client /]# redis-cli -h redis
redis:6379>

```

---

The name and port to which we connect is controlled by the `Service` object. If instead of the above example I had:

```
apiVersion: v1
kind: Service
metadata:
  name: bob
spec:
  selector:
    app: redis
  ports:
  - port: 2000
    targetPort: redis

```

I would need to connect like this:

```
[root@client /]# redis-cli -h bob -p 2000
bob:2000>

```

---

For more information:

---
Tags: kubernetes, networking
---


# Question
Title: Create a folder in slave node using Jenkins pipeline groovy script
I have a Jenkins job which runs on a slave node on another machine, both master and slave run on windows. The slave node is being run as a windows service. The main repository has git submodule included. After checking-out the code for both the main and sub module repositories, I need to create a folder inside of the submodule folder and write a file into it with some basic deployment details like tag, version, etc. Structure is something like this:

***`main -> submodule -> {newfolder} -> {newfile}`***

I am using the mkdir() to create the folder, but it is not being created. I have also tried the dir() method. But nothing seems to be working. Can anyone help on this:

1. Do I need to provide elevated permissions set for the windows service used to trigger the slave node?
2. Do I need to provide permissions at folder level?

Any other check that I am missing, please help.

# Answer
> 0 votes
Issue got resolved with the use of File Operations Plugin methods like `folderCreateOperation` & `fileCreateOperation`. Example code snippet below:

```
def path = "${workspace}\submodule\newFolder"
fileOperations([folderCreateOperation(folderPath: path)])
dir(path) {
    fileOperations([fileCreateOperation(fileName: 'newFile.properties', fileContent: 'Git_Tag=${env.Git_Tag}')])
}

```

---
Tags: jenkins-pipeline, git, permissions
---


# Question
Title: Jenkins Credentials Manager + Active Choices
I want to access Jenkins Credentials to authenticate with Git **before** the pipeline script - to fill Active Choices parameter.

In the pipeline I simply do it with `withCredentials`. But during pre-pipeline stage (i.e. Active Choices parameter) Hudson extensions such as `withCredentials` or `sshAgent` are not accessible. Currently I execute groovy `git ls-remote -h git@gitrepo.example.com:repo.git` with unencrypted key in jenkins\_home directory (which is not a good idea).

I know that there is some possibility to import and construct Java objects by reading Jenkin's and its plugins' source code - but this seems endless.

So: is it possible to somehow easily import and apply Hudson extensions to current Groovy script or does anyone have some ready solution for this (apparently nobody published anything about such case)?

# Answer
It sounds to me like you're already aware of this, but there are a couple easy ways to do this, and a couple hard ways to do this.

The easy ways:

* Make your repo available for checkout without SSH keys or authentication credentials.
* Manually add an SSH keypair for repo checkout to the Jenkins user on your Jenkins master node (since Active Choice Groovy scripts run on the master node) (i.e. don't use the Credentials store).

The hard ways:

* Use the Jenkins Java API in your Active Choices code to extract credentials from the credentials store. API docs are available for the credentials store and the ssh credentials type. There is no documentation on how to use the Java classes available in these plugins, so it's up to you to figure it out yourself.
* Create a secondary "meta" job to update the parameters in the original Jenkins job (including Active Choices scripts) - I describe this a bit below.

---

If you can't do any of the easy solutions for security reasons, there isn't an easy, straightforward way to update Active Choice parameters based on the contents of a git repo. This is because:

1. Like you said, "during pre-pipeline stage (i.e. Active Choices parameter) Hudson extensions such as withCredentials or sshAgent are not accessible".
2. The configuration for parameters, including Active Choice parameters, is taken from the *previous* run of that Pipeline, not the current one. Meaning that, to update your parameters from within your Pipeline code, you'll need to run your Pipeline, which defeats the point of what you want to do.

There is a solution for 1., which is to use Scripted Pipelines instead of Declarative, but that won't get around the problems of 2.

The solution that I came up with when I ran into this issue is to create a second Jenkins job (I call it a "meta" job) which updates the parameters of the original job, including Active Choices scripts. This second meta job is triggered by a git hook on the repository that I use to fill the options in my Active Choices parameters. This has the advantage that you do not need to run the original job's Pipeline in order to update its parameters, solving the issues in 2. Also, because it's still a Pipeline job, you can use normal Pipeline steps, thus allowing you to access the credentials store.

My job looks (roughly) like this - I simplified it a lot to make it fit here, so you'll need to do a bunch of tweaking to get it working the way you want. There are probably a ton of errors and bugs in this because I ripped apart an existing script to make this. A few things to note:

* This makes heavy use of Jenkins APIs, so you'll need to either disable the script sandbox or whitelist a ton of functions in the Jenkins security manager in order to get this to run
* This is still technically a Scripted Pipeline even though it looks much more like a normal Groovy script than a Pipeline file
* Because this is a Pipeline, you can use steps like `withCredentials` to check out repositories using the credentials store.

```
import groovy.json.JsonOutput

import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript

import org.biouno.unochoice.*
import org.biouno.unochoice.model.*

def metadataUrl = 'ssh://git@**************/metadata.git'
def metadataBranch = 'master'

def metadata = [:]

node('master') {
  git(
    url: metadataUrl,
    branch: metadataBranch,
    credentialsId: 'jenkins',
    changelog: false,
  )

  def dataDir = "${pwd()}/myJsonFiles"

  // can't use File.eachFileMatch() due to:
  // https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches
  def files = new File(dataDir).list().findAll() { f->
    FilenameUtils.getExtension(f) == 'json'
  }

  files.each() { f->
    // TODO: nice error messages if files are misformatted
    def name = FilenameUtils.removeExtension(f)
    def data = readJson(file: "${dataDir}/${f}")
    metadata[name] = data
  }
}

// ChoiceParameterDefinition is the class name for the built-in static choice parameter.
// CascadeChoiceParameter is the class name for the Active Choices dynamic choice parameter.

// begin first parameter
def fileParam = new ChoiceParameterDefinition(
  'file',
  'The JSON file to use',
)
fileParam.setChoices(metadata.keySet())
// end first parameter

// begin second parameter
def metadataJson = JsonOutput.toJson(metadata)

def scriptText = """
import groovy.json.JsonSlurper

def slurper = new JsonSlurper()
def metadata = slurper.parseText('${metadataJson}')

return metadata[file]['versions']
"""
def mainScript = new SecureGroovyScript(scriptText, true)
def fallbackScript = new SecureGroovyScript('return ["Error encountered - see logs"]', true)
def activeChoiceScript = new GroovyScript(mainScript, fallbackScript)

def versionParam = new CascadeChoiceParameter(
  'version',
  'The version to use',
  activeChoiceScript,
  'PT_SINGLE_SELECT',
  'file',
  false,
)
// end second parameter

def paramProp = new ParametersDefinitionProperty(fileParam, versionParam)

// this is the full name of the actual job which needs dynamic parameters
def job = Jenkins.instance.getItemByFullName('UNIX/deploy_to_environment/master')

// There is no "setProperty" - we need to remove and replace.
// removeProperty is safe to run even if no matching properties are set on the job.
// However, this method only removes one property per method call.
// Theoretically, this means the job could accumulate multiple conflicting
// ParametersDefinitionProperty properties.
// TODO: run removeProperty in a while loop to eliminate all matching properties for extra safety.
job.removeProperty(ParametersDefinitionProperty)

job.addProperty(paramProp)

```
> 0 votes

# Answer
I'm not using the git credential type, but we use a secret stored in the credential store as an API token, that is used to call away to an endpoint to populate a select dropdown.
I'm sure you could modify to pull the creds from a different secret. (Also I'm not a groovy/Java dev so there might be a cleaner way to do this).

This is how it looks in our pipeline script

```
properties(
    [
        parameters(
            [
                [
                  $class: 'ChoiceParameter',
                  choiceType: 'PT_SINGLE_SELECT',
                  name: 'Environment',
                  description: 'The environment to deploy to',
                  filterLength: 1,
                  filterable: true,
                  script: [
                    $class: 'GroovyScript',
                    fallbackScript: [
                        classpath: [],
                        sandbox: false,
                        script:
                            'return[\'Could not load envs\']'
                    ],
                    script: [
                        classpath: [],
                        sandbox: false,
                        script:
                            '''
                            #!/usr/bin/env groovy
                            import jenkins.model.*
                            import groovy.json.JsonSlurper

                            def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
                                org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl,
                                Jenkins.instance,
                                null,
                                null
                            );

                            def apiToken = ''
                            for (c in creds){
                              if(c.getId() == '[CREDENTIAL ID FOR API TOKEN]'){
                                apiToken = c.getSecret()
                                break
                              }
                            }

                            def get = new URL("https://example.com/envs").openConnection()
                            get.setRequestProperty("Accept", "application/json")
                            get.setRequestProperty("Authorization", "Bearer "+apiToken)
                            get.setUseCaches(false)
                            get.setDoOutput(true)
                            def getRC = get.getResponseCode()
                            def response = get.getInputStream().getText()
                            def jsonSlurper = new JsonSlurper()
                            def responseObject = jsonSlurper.parseText(response)
                            return responseObject['data']
                            '''
                    ]
                  ]
                ]
            ]
        )
    ]
)

```

Hope it helps!
> 0 votes

---
Tags: jenkins, groovy, hudson
---


# Question
Title: Read and parse json file from workspace on slave node
I have a Jenkins job which runs on a slave node on another machine, both master and slave run on windows. The slave node is being run as a windows service. I am unable to read a json file from workspace in the slave node and parse it. The JSON file structure is like given below. I need to read the EmailProperties object and modify each of the properties and save the json file again. I have tried multiple suggestions on readFile() & readJSON(), but none of them is working. Any help on this would be highly appreciated.

**JSON file:**

```
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "EmailProperties": {
      "MailPort": "587",
      "MailServer": "mydomainmailserver.outlook.com",
      "Password": "password123$",
      "Sender": "company@domain.com"
    }
}

```

**Properties file:**

```
[transformation]
json_dev_EmailProperties.MailPort = 663
json_dev_EmailProperties.MailServer = devmailserver.outlook.com
json_dev_EmailProperties.Password = DevPassword123$
json_dev_EmailProperties.Sender = company@devmailserver.outlook.com

```

# Answer
Following is the code that worked for me, if there is any other better way to do this, suggestions are most welcome.

**Main Method:**

```
def transformjsonfile(propertiesPath, jsonfilepath) {

  // Load Properties file
  Properties props = new Properties()
  props.load(new StringReader(readFile(propertiesPath)))

  // Load json file
  def json = jsonParseFile(jsonfilepath)

  // Transform json
  json = transformValues(props, json)

  // Write back the tranformed config to the json file
  formatAndWriteBackJson(json)
}

```

**Helper methods:**

```
def jsonParseFile(def jsonfilepath) {
    def fileContent = readFile(file: jsonfilepath, encoding: "UTF-8")
    def jsonSlurper = new JsonSlurperClassic()
    def data = jsonSlurper.parseText(fileContent.replaceAll("\\s", "").replaceAll("\uFEFF", ""))
    return data
}

def formatAndWriteBackJson(json)
{
  def jsonOut = new JsonBuilder(json).toPrettyString()
  writeFile file: jsonfilepath, text: jsonOut.toString()
}

def transformValues(props, json) {
  for (String name: props.keySet()) {
    String givenValue = props.getProperty(name);
    String value = givenValue.trim();
    if (name.startsWith("json_${env.Environment}_")) {
      splitarray = name.split("json_${env.Environment}_")
      jsonvalue = splitarray[1]
      key = "${jsonvalue}"
      transformvalue = "${value}"
      def someString = "${key}"
      def someChar = '.'
      int count = 0;
      for (int i = 0; i < someString.length(); i++) {
        if (someString.charAt(i) == someChar) {
          count++;
        }
      }
      keyvalue = "json"
      splitarray = key.split('\\.')
      lab1: for (int j = 0; j <= count; j++) {
        keyvalue = keyvalue + "." + splitarray[j]
        jsonvalue = Eval.me('json', json, "${keyvalue}")
        if (jsonvalue == null) {
          break lab1;
        }
        if (jsonvalue != null) {
          println 'condition met'
          if (j == count) {
            Eval.me('json', json, "${keyvalue} ='$transformvalue'")
          }
        }
      }
    }
  }
  return json
}

```
> 0 votes

---
Tags: jenkins-pipeline, pipeline, json
---


# Question
Title: Unable to ssh into EC2 instance to the peered VPC which is in different region
It's a very simple setup in which there are two EC2 instances each in a different region but under the same account. Both are peered.

Requester EC2 EC2Virginia has the following details:

```
Public IP: 34.201.42.246
Private IP: 172.30.3.42
Subnet is in US-east-1a
VPC CIDR: 172.30.0.0/16
Allow requester VPC to resolve DNS of hosts in accepter VPC to private IP addresses is enabled for both requester and accepter.
Route: Destination is 172.31.0.0/16 using peering connection
Security group accepts all inbound and outbound traffic

```

Accepter EC2 EC2Ireland has the following details:

```
Public IP: 3.248.183.191
Private IP: 172.31.28.244
Subnet is in eu-west-1c
VPC CIDR: 172.31.0.0/16
Allow requester VPC to resolve DNS of hosts in accepter VPC to private IP addresses is enabled for both requester and accepter.
Route: Destination is 172.30.0.0/16 using peering connection
Security group accepts all inbound and outbound traffic

```

I am trying to do ssh from EC2Virginia to EC2Ireland and it is failing.

```
[ec2-user@ip-172-30-3-42 ~]$ ssh -i "irelandconnect.pem" ec2-user@172.31.28.244
ssh: connect to host 172.31.28.244 port 22: Connection timed out

```

I executed following route command on EC2Virginia:

```
[ec2-user@ip-172-30-3-42 ~]$ routel
         target            gateway          source    proto    scope    dev tbl
        default         172.30.0.1                                     eth0
169.254.169.254                                                        eth0
    172.30.0.0/ 20                     172.30.3.42   kernel     link   eth0
      127.0.0.0          broadcast       127.0.0.1   kernel     link     lo local
     127.0.0.0/ 8            local       127.0.0.1   kernel     host     lo local
      127.0.0.1              local       127.0.0.1   kernel     host     lo local
127.255.255.255          broadcast       127.0.0.1   kernel     link     lo local
     172.30.0.0          broadcast     172.30.3.42   kernel     link   eth0 local
    172.30.3.42              local     172.30.3.42   kernel     host   eth0 local
  172.30.15.255          broadcast     172.30.3.42   kernel     link   eth0 local
            ::/ 96     unreachable                                       lo
::ffff:0.0.0.0/ 96     unreachable                                       lo
    2002:a00::/ 24     unreachable                                       lo
   2002:7f00::/ 24     unreachable                                       lo
   2002:a9fe::/ 32     unreachable                                       lo
   2002:ac10::/ 28     unreachable                                       lo
   2002:c0a8::/ 32     unreachable                                       lo
   2002:e000::/ 19     unreachable                                       lo
   3ffe:ffff::/ 32     unreachable                                       lo
        fe80::/ 64                                   kernel            eth0
            ::1              local                   kernel              lo local
fe80::5c:7dff:fea5:1d59              local                   kernel            eth0 local
      multicast

```

Please help resolve this issue.

# Answer
> 0 votes
I added routes in each of the subnets on both requestor and receiver side and it worked.

---
Tags: amazon-web-services, amazon-ec2, aws-vpc
---


# Question
Title: Azure Devops deploy docker image to ACR using deployment job
I'm trying to deploy a docker image to Azure Container Registry via an Azure Devops pipeline. Now this works fine when I run it with this script:

```
trigger:
- master

variables:
  # Container registry service connection established during pipeline creation
  dockerRegistryServiceConnection: 'some_id'
  imageRepository: 'worker'
  containerRegistry: 'microcontainerapptest.azurecr.io'
  dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
  tag: '$(Build.BuildId)'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'

stages:
- stage: Build
  displayName: Build and push stage
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: $(vmImageName)
    steps:
    - task: Docker@2
      displayName: Build and push an image to container registry
      inputs:
        command: buildAndPush
        repository: $(imageRepository)
        dockerfile: $(dockerfilePath)
        containerRegistry: $(dockerRegistryServiceConnection)
        tags: |
          $(tag)

```

However, I want to actually use a deployment job so I can run the pipeline in different environments. Therefore I updated the .yml like this:

```
trigger:
- master

variables:
  # Container registry service connection established during pipeline creation
  dockerRegistryServiceConnection: 'some_id'
  imageRepository: 'worker'
  containerRegistry: 'microcontainerapptest.azurecr.io'
  dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
  tag: '$(Build.BuildId)'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'

stages:
- stage: Build
  displayName: Build and push stage
  jobs:
  - deployment:
    displayName: Build docker image
    environment: $(DEPLOY_ENVIRONMENT)
    strategy:
      runOnce:
        deploy:
          steps:
          - task: Docker@2
            displayName: Build and push an image to container registry
            inputs:
              command: buildAndPush
              repository: $(imageRepository)
              dockerfile: $(Build.SourcesDirectory)/Dockerfile
              containerRegistry: $(dockerRegistryServiceConnection)
              tags: |
                $(tag)

```

Making a deployment job out of this. Now when I run the pipeline like this I get an error

> Unhandled: No Dockerfile matching /home/vsts/work/1/s/Dockerfile was found.

So it seems like the dockerfilePath is not valid anymore when I run it as a deployment job. I have searched but don't have a clue as to why this would be the case, does anybody know the answer to this?

# Answer
You need to explicitly check out your source code, because:

> A deployment job doesn't automatically clone the source repo. You can checkout the source repo within your job with `checkout: self`. Deployment jobs only support one checkout step.

```
strategy:
  runOnce:
    deploy:
      steps:

      - checkout: self

      - task: Docker@2
        displayName: Build and push an image to container registry
        inputs:
          command: buildAndPush
          repository: $(imageRepository)
          dockerfile: $(Build.SourcesDirectory)/Dockerfile
          containerRegistry: $(dockerRegistryServiceConnection)
          tags: |
            $(tag)

```
> 0 votes

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


# Question
Title: How can you do pre-merge testing in trunk based development?
Currently, we use a simple branching strategy, with a single main branch and one layer of feature branches; no branches on branches on branches. We also have many pipelines that run against each PR to check the code before it is merged to the main branch, including but not limited to,

* code quality
* linting
* security assurance

In a trunk-based approach, how does one run these tests before code is merged, without a PR?

I have seen Trunk Based Development - release branch testing but it did not fully answer my question. Thanks in advance for your patience with a n00b question :D

# Answer
You can still use pull requests with Trunk-Based Development. Especially with larger teams, using short-lived feature branches, you would open a pull request into the trunk, which would start the build process. Depending on your environment and desire to have rapid merges, you could merge the pull request automatically, perhaps based on things like no new style violations, sufficient code coverage, tests pass, and no new static analysis violations, and defer the human review for later.
> 2 votes

---
Tags: git, automation, testing, tdd
---


title: What exactly is a buildpack in DevOps?

text:
# Question
Title: What exactly is a buildpack in DevOps?
I am familiar with the term buildpack from a platform called Heroku. But I am not sure if it's a Heroku-specific term, or if it exists more broadly in DevOps nomenclature?

When I google, I see plenty of articles about buildpacks that *don't* mention Heroku, so I guess it's more general. If that's the case, what exactly is it? And how does it differ from something like a docker image? Or are they the same things with different names?

# Answer
> 1 votes
You asked several questions one of which was answered in another question and I believe the other answer is only half correct.

> If \[it being a general DevOps technology is\] the case, what exactly \[is a buildpack\]? And how does it differ from something like a docker image? Or are they the same things with different names?

Yes buildpacks are a general DevOps tech atleast now (you can read why farther down below with the history.) Docker images and buildpacks are two different technologies. Buildpacks produce container images. Docker Images are container images. Buildpacks are hence different then Docker Images, but related to them. But, using Docker there is also a way to produce these images called a Dockerfile. Buildpacks are thus much more like Dockerfiles than they are like Docker Images.

Now I would like to explain the difference between Dockerfiles and Buildpacks. A Dockerfile is usually created by a developer for every app they make. For example, first they pull in a Programming language's docker image (e.g. NodeJS's), then they copy over their files to the container (e.g. the project's app specific code), then install dependencies (e.g. yarn install), then they compile code (e.g. compile typescript code), then they define the way to run the app (e.g. npm start), then the Dockerfile has done it's job and has created the system at a particular state and then an image is created.

Now if you've ever used heroku you know that you don't need Docker or Dockerfiles to run your app you only need your project code and heroku automatically figures out how to create a container image and run your code. It will do things such as see there is a package.json in your project code and apply a Node.js Buildpack to the code to build a container image. That is the magic of Buildpacks.

> I am familiar with the term buildpack from a platform called Heroku. But I am not sure if it's a Heroku-specific term, or if it exists more broadly in DevOps nomenclature?

Yes it now does exist more broadly in a sense, and the history of buildpacks started with Heroku; here's a bit on that history:

> ## Buildpacks history
>
> Buildpacks were first conceived by Heroku in 2011. Since then, they have been adopted by Cloud Foundry and other PaaS such as Google App Engine, Gitlab, Knative, Deis, Dokku, and Drie.
> \- buildpacks.io

> When I google, I see plenty of articles about buildpacks that don't mention Heroku, so I guess it's more general.

Yep. It's general and sometimes when a tech project diverges into several projects from several different companies such as when one tech like heroku's buildpacks is recreated by: "Cloud Foundry and other PaaS such as Google App Engine, Gitlab, Knative, Deis, Dokku, and Drie"; someone or some team is kind enough to give us a single standard to use and this is how Cloud Native Buildpacks was born:

> The Cloud Native Buildpacks project was initiated by Pivotal and Heroku in January 2018 and joined the Cloud Native Computing Foundation in October 2018. The project aims to unify the buildpack ecosystems with a platform-to-buildpack contract that is well-defined and that incorporates learnings from maintaining production-grade buildpacks for years at both Pivotal and Heroku.
>
> Cloud Native Buildpacks embrace modern container standards, such as the OCI image format. They take advantage of the latest capabilities of these standards, such as cross-repository blob mounting and image layer "rebasing" on Docker API v2 registries.
> \- buildpacks.io

# Answer
> 2 votes
They are the same thing with different names. It's a general term.

---
Tags: terminology, builds, images
---


# Question
Title: Setup multiple Raspberry Pi different network configurations
For multiple projects we are setting up 2 to 6 RPi's per project. Each project runs on a different network and for some of these networks we can use DHCP, for others the RPi's have to connect using a static IP address.

Also every RPi needs a different hostname in sequential order. For instance for a project with three RPi's, the hostnames need to be PROCCESS1, PROCESS2, PROCESS3.

All RPi's run the exact same software and every RPi has a single monitor connected.

The current workflow is:

1. Burn a prepared OS image for every RPi on a microSD
2. Boot up the RPi using the microSD and manually set the hostname
3. If needed, set the IP address to a static one
4. Turn on the overlay file system so the system is read-only
5. Repeat for the amount of RPi's needed

This is a tedious task where errors are made and takes a lot of time. Step 1 can not be automated, since we don't have the hardware (altough the EtcherPro would eventually save a lot of time). Automating step 3 and 4 would be great if that can be realized. I've read a bit about Ansible and also encountered Chef and Puppet but I haven't dived into any of them yet.

Is using Ansible with playbooks a good direction to develop further? Would it be possible to automate the setup using this tool? Is there a better/easier solution or would it not be possible at all? If someone has some tips or can guide in the right direction that would be great.

# Answer
> 2 votes
Even without Ansible or other config management tool, there's no reason any of those steps need to be manual: you could drive everything with a shell script, thus reaping all the benefits of automation: no more errors, consistent deployments, and faster configuration. Using Ansible can help make the process more modular and more structured, but it doesn't fundamentally allow you to do anything new.

---

Ignoring the question of what tooling you use to drive the configuration, I'd like to suggest an option that you may not have considered: it's possible to perform all the configuration on the image *before* burning it onto a microsd card. You can mount the raspberry pi os image on a local directory, and then make all your configuration changes there. I use a process like this:

1. Download and unzip the raspberry pi os image
2. Make a working copy of the image (this way you can re-use the base image multiple times to create different configured images):

```
# cp 2022-01-28-raspios-bullseye-armhf-lite.img work.img

```

I like to extend the image a bit so there's room for installing new software:

```
# truncate -s 2500MB work.img

```
3. Attach the work image to a loop device:

```
# losetup -fnP --show work.img
/dev/loop0

```
4. Grow the filesystem to use the additional space:

```
# parted /dev/loop0 resizepart 2 100%
# e2fsck -f /dev/loop0p2
# resize2fs /dev/loop0p2

```
5. Mount the filesystems locally:

```
# mount /dev/loop0p2 /mnt
# mount /dev/loop0p1 /mnt/boot

```

---

Now you're in a position where you can create and modify configuration files on the image, in order to...

* Configure networking
* Configure the hostname
* Enable ssh
* Configure wifi
* Install ssh keys
* Etc.

But what if you want to do other things, like update or install packages? If you install the `qemu-user-static` package and properly configure the `binfmt_misc` module (modern versions of the `qemu-user-static` package will do this for you automatically), you will be able to run Raspberry Pi binaries on your host. This allows you to run commands inside the image, like this:

```
# systemd-nspawn -D /mnt apt update
# systemd-nspawn -D /mnt apt upgrade -y
# systemd-nspawn -D /mnt apt install -y git

```

Or inject a shell script:

```
# systemd-nspawn -D /mnt --bind=$PWD/config.sh:/config.sh sh /config.sh

```

Here I'm using `systemd-nspawn`, which is a little like `chroot` (in this example), except it takes care of mounting special filesystems like /sys and /proc and has all sorts of interesting options (like the `--bind` option for bind mounting files or directories into the image).

---

When you're all done, unmount the filesystem and disconnect the loop device:

```
# umount /mnt/boot /mnt
# losetup -d /dev/loop0

```

And write the customized image to an sd card:

```
# dd if=work.img of=/dev/sdb bs=4M

```

---

You can wrap the entire process described here in a script, and have it take parameters to configure networking (specify a static address or use dhcp), etc.

---
Tags: ansible, deployment, chef, raspberry-pi-os
---


# Question
Title: How to automatically update Swarm services when the Docker daemon restarts
I'm using Docker Swarm, and I have `condition: always` in the `restart_policy` of my compose file, so my services are started automatically when the system reboots or the Docker daemon is restarted.

What I'm trying to achieve is to also have the services pull and run the *latest* image when the system reboots or the daemon is restarted. This is for an IoT device, so yes, I really do want to do this.

Now, if I manually take down and restart the stack, or if I use `docker service update --force --image my-image:latest my-service`, then the latest image is pulled and ran. But if I restart the system, it just keeps running the old image, and doesn't pull the latest one.

I could work around this by removing the restart policy and using systemd to manage lifecycle instead, but I really don't want that extra hassle or complexity, and I'm not even sure how to work that to restart services that crash.

Is there some way to achieve this with Docker Swarm alone?

# Answer
You don't need a restart policy with swarm mode. Swarm mode will constantly try to reconcile any differences between the current and target state. I've seen cases where the restart policy enforced by the docker engine, and the implicit reconciliation in swarm mode have conflicted and resulted in issues. The restart policy would also restart the stopped container which would implicitly break the goal to use a new image since the image can not change for the life of a container. Swarm mode, conversely, will recreate any stopped containers with a new container.

To have swarm use the current value of a tag, rather than resolving that tag to an image digest on the initial deploy, you need `docker stack deploy --resolve-image ...`. Note that I haven't tested if this will pull new images, I've only needed to use the feature to use locally built images that shouldn't be pulled from a registry. If Swarm mode doesn't pull new images, you'll also want an extra process to pull your image periodically.
> 2 votes

# Answer
This is one approach to keeping swarm upto date, only runs after startup, but does continuously monitor based on period schedule in minutes.

https://github.com/djmaze/shepherd
> 0 votes

---
Tags: docker, docker-compose, docker-swarm, systemd
---


# Question
Title: kubectl asking for username (k8s cluster created via kops)
I created a kubernetes cluster using `kops` and deployed it in AWS (not EKS manual cluster using `kops`).

Then I export in my local machine the configuration like `kops export kubecfg --state ${KOPS_STATE_STORE} --name ${NAME}`

Then running any kubectl command asks for a username, even `kubectl` version

```
 kubectl version
Please enter Username:

```

PS: If I `ssh` into bastion host then `ssh` into k8s master node, kubectl works fine and its configuration is referring to local user created.

My local config created from export command into `~/.kube/config` looks like:

```
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: fakedata=
    server: https://api-test-intern-doesntmatter.eu-central-1.elb.amazonaws.com
  name: test-internet.k8s.local
contexts:
- context:
    cluster: test-internet.k8s.local
    user: test-internet.k8s.local
  name: test-internet.k8s.local
current-context: test-internet.k8s.local
kind: Config
preferences: {}
users:
- name: test-internet.k8s.local
  user: {}

```

And with the config above I cannot do any `kubectl` command. Where can I find the username and password for `kubectl`? I have set authentication as RBAC for the cluster and no limitations.

I read all article here https://kubernetes.io/docs/reference/access-authn-authz/authentication/ and still do not understand what is the default username password why am I asked for such credentials I haven't created any role or user.

# Answer
> 1 votes
I solved this temporarily with not the safest solution, but is working When creating secret with kops named admin, can use that to generate user field in exported kops config by adding also

`--admin` in the export command

# Answer
> 0 votes
If you are using test clusters then just use

```
kops update cluster ${NAME} --yes --state ${KOPS_STATE_STORE} --admin

```

Read more at

https://github.com/kubernetes/kops/blob/master/docs/releases/1.19-NOTES.md#changes-to-kubernetes-config-export

# Answer
> 0 votes
you can fix this by entering below command

```
kops export kubecfg --admin

```

---
Tags: kubernetes, kubectl, kops
---


# Question
Title: In Ansible, how do I assign a hostvar to a playbook's host?
The directory of my Ansible project has the following structure:

```
project/
  playbook.yml
  host_vars/
    localhsot.yml
  roles/
    ...
    terraform-provision/
      ...
  terraform/
      ...

```

Here's *project/playbook.yml*:

```
- hosts: localhost
  tasks:
  - name: trigger role
    include_role:
      name: terraform-provision
- hosts: hostvars['localhost'].aws_instance_host_group
  tasks:
  - name: debugging
    debug:
      var: hostvars['localhost'].aws_instance_host_group

```

Here's the relevant part of *project/host\_vars/localhost.yml*:

```
hostvars['localhost'].aws_instance_host_group
aws_instance_host_group: "aws_instance"

```

Here's the relevant part of *project/roles/terraform-provision/tasks/main.yml*:

```
- name: Add the provisioned AWS instance to the inventory
  add_host:
    name: "{{ aws_instance_public_ip.value }}" # set using set_fact elsewhere in file
    ansible_user: "{{ aws_instance_user_name }}"
    groups: "{{ aws_instance_host_group }}"

```

When I execute *project/playbook.yml*, it throws the following error when trying to connect to the host created by the *terraform-provision* role:

```
[WARNING]: Could not match supplied host pattern, ignoring: hostvars['localhost'].aws_instance_host_group

```

However, the debugging task of *project/playbook.yml* prints the group's name (aws\_instance) successfully.

What am I missing? Is there a better approach to achieve the same thing?

# Answer
> 2 votes
To be evaluated, a variable must be closed in quoted double curly braces, e.g.

```
- hosts: "{{ hostvars.localhost.aws_instance_host_group }}"

```

The dot notation simplifies the code.

---

<sup>

**Minimal reproducible example**

```
shell> cat pb.yml
---
- hosts: localhost
  gather_facts: false
  tasks:
    - set_fact:
        aws_instance_host_group: aws_instance
    - add_host:
        name: 10.1.0.61
        groups: "{{ aws_instance_host_group }}"

- hosts: "{{ hostvars.localhost.aws_instance_host_group }}"
  gather_facts: false
  tasks:
    - debug:
        var: groups
    - debug:
        var: inventory_hostname

```

```
shell> cat hosts
localhost

```

```
shell> ansible-playbook -i hosts pb.yml

PLAY [localhost] *****************************************************************************

TASK [set_fact] ******************************************************************************
ok: [localhost]

TASK [add_host] ******************************************************************************
changed: [localhost]

PLAY [aws_instance] **************************************************************************

TASK [debug] *********************************************************************************
ok: [10.1.0.61] =>
  groups:
    all:
    - 10.1.0.61
    - localhost
    aws_instance:
    - 10.1.0.61
    ungrouped:
    - localhost

TASK [debug] *********************************************************************************
ok: [10.1.0.61] =>
  inventory_hostname: 10.1.0.61

PLAY RECAP ***********************************************************************************
10.1.0.61: ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
localhost: ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

```
</sup>

---
Tags: ansible
---


title: validating map of objects

text:
# Question
Title: validating map of objects
I am trying to validate a map of objects that is typed as below :

```
variable "ecs_config_map" {
  type = map(object({
    cpu     = number
    memory  = number
    desired = number

    capabilities = list(string)
    launch_type  = string
  }))
}

```

The value for the variable looks like :

```
ecs_config_map = {
  driver = {
    cpu     = 256
    memory  = 512
    desired = 0

    capabilities = ["FARGATE"]
    launch_type  = "FARGATE"
  }
  aggregator = {
    cpu     = 256
    memory  = 512
    desired = 0

    capabilities = ["FARGATE"]
    launch_type  = "FARGATE"
  }
}

```

---

Now, I want to perform some basic validation, but I cannot seem to get the syntax right.

```
 validation {
    condition = contains(["EC2", "FARGATE", "EXTERNAL"], var.ecs_config_map[*]["launch_type"])
    error_message = "Only EC2, FARGATE, EXTERNAL are allowed values for launch_type."
  }

```

This threw `Invalid value for "list" parameter: list of bool required.`

---

Debugging on `terraform console` described :

```
> type(var.ecs_config_map)
map(
    object({
        capabilities: list(string),
        cpu: number,
        desired: number,
        launch_type: string,
        memory: number,
    }),
)
> type(var.ecs_config_map["driver"])
object({
    capabilities: list(string),
    cpu: number,
    desired: number,
    launch_type: string,
    memory: number,
})
> type(var.ecs_config_map[*])
tuple([
    map(
        object({
            capabilities: list(string),
            cpu: number,
            desired: number,
            launch_type: string,
            memory: number,
        }),
    ),
])

```

which indicated that my problem was because I was trying to iterate over all the objects in the variable. I am using a splat expression when doing `var.ecs_config_map[*]` which converts the whole map into a tuple of maps of objects.

---

Then I tried to use a `for` expression to perform the validation

```
 validation {
    condition = can(for task in var.ecs_config_map : contains(["EC2", "FARGATE", "EXTERNAL"], task["launch_type"]))
    error_message = "Only EC2, FARGATE, EXTERNAL are allowed values for launch_type."
  }

```

And I got thrown `The condition for variable "ecs_config_map" can only refer to the variable itself, using var.ecs_config_map.`

`for_each` did not work either.

---

Am I messing up the syntax of the validation somewhere? Or am I asking too much from terraform by attempting validation of a complex type?

# Answer
> 2 votes
You can validate your variable with the following expression:

```
validation {
  condition     = length([for launch_type in values(var.ecs_config_map)[*].launch_type: launch_type if !contains(["EC2", "FARGATE", "EXTERNAL"], launch_type)]) <= 0
  error_message = "Only EC2, FARGATE, EXTERNAL are allowed values for launch_type."
}

```

This might seem complex so let's brake it donw.

We can extract the launch types from `ecs_config_map` with the following `for` expression:

```
output "launch_types" {
  value = [for launch_type in values(var.ecs_config_map)[*].launch_type : launch_type]
}

```

The output of this would be something like:

```
launch_types = [
  "FARGATE",
  "FARGATE",
]

```

Moving on, we would want to filter out those launch types which are not in the allowed types array (`["EC2", "FARGATE", "EXTERNAL"]`). We can do this as such:

```
output "not_allowed_launch_types" {
  value = [for launch_type in values(var.ecs_config_map)[*].launch_type: launch_type if !contains(["EC2", "FARGATE", "EXTERNAL"], launch_type)]
}

```

If the input is correct, this should output an empty array, otherwise we will have the incorrect launch types as the output.

Final step is to validate if we have any incorrect launch types. We can do this with the `length` function, if the length of the array with the incorrect launch types is greater than `0`, we have an invalid input.

---
Tags: terraform
---


# Question
Title: Why use configuration management tools in the world of modern cloud?
Configuration management tools like Ansible, Chef, Puppet, and Saltstack allows us to configure a cluster of blank machines to help install and deploy an application. For example, with Ansible, we can set up a cluster of newly provisioned compute servers to e.g. install a specific version of Go, edit O.S. properties, or modify the firewall.

Are these tools still needed in today's world where we have cloud providers that offer managed k8s, docker registries, and machine images for us? For example, on AWS:

* We can configure an OS environment manually once and save it as an AMI, then simply just use this AMI for the cluster. Alternatively, we can just use Fargate.
* The Docker image will contain all needed dependencies, and will also have an entrypoint to run the application itself.
* Managed k8s like EKS mean we don't have to worry about setting up the control plane, and updating the cluster is as simple as issuing a kubectl command to the control plane.

Assuming one uses EKS + ECR + something like Terraform to provision the resources, what value would Ansible, Chef, etc. provide? Why would we want to include them into our stack? Or does modern cloud services make them unneccesary?

My question is inspired from this guide, which recommends using EKS + Terraform + Ansible... but the Ansible playbook is just 2 kubectl commands that can just be replaced by a shellscript, right? Why introduce an entirely new technology in our stack?

# Answer
> 3 votes
# What value does Ansible have in a modern cloud environment?

As the comments say, it depends on your needs. But I think there is value in considering this sort of thing, so I'm going to answer this from two angles. I've spent the last dozen years working in large scale cloud environments and I've seen ansible used for all sorts of weird yet handy things.

## Does ansible make sense in the example you cited?

Your guide from Dhruvin Soni is using ansible to manage which services are running in your kubernetes environment. This is a problem that should be solved with some tool. I would not try to maintain all of my kubernetes services with a shell script. I'm a fan of the shell, but building a bespoke solution for this seems like a waste of time.

So we have a problem and we need a tool. Is ansible a good tool for this? I'd say yes. I haven't seen it used that way in any of the places I've worked, but I wouldn't object to maintaining the state of kubernetes this way.

If you're looking for something more cloud-native then I'd recommend kustomize. They even describe themselves as "Kubernetes native configuration management" and it provides features for patching your YML configs to add tags, namespaces, or whatever you need. This sort of power is definitely handy when managing complex kubernetes environments.

## Does ansible still have a place in modern cloud environments?

So let's say you're using kustomize or Argo to manage your kubernetes environments. Wouldn't that eliminate the need for ansible? Not necessarily. I've seen a few places that ansible would still be a good tool to choose:

1. You're going to want to build your own docker images to run in the cloud and ansible is a perfectly valid and helpful tool for being able to get those built.
2. Maintaining developer desktop environments. This is like the old servers as pets model. The developer doesn't want to lose all of their files every time there is an upgrade. Running ansible works fine in Macs or Windows or Linux and can act differently in those OS's where needed.
3. Almost everybody has some legacy servers or some service they're managing outside of the "modern cloud". Ansible is still a great choice for the legacy stuff.

# Answer
> 3 votes
Generally, things like Packer and Terraform handle most straight infra requirements best in the cloud. Of course, if you have kubernetes up already, it’s the same deal. A packer (or other AMI) image and a docker image are both similar in that they can/should be configured to come up ready for use.

Ansible can still be useful though. As much as we’d all like to avoid it, it is hard to get rid of 100% of long running servers. Ansible is helpful to manage servers already around. Some people also like it for the same kind of thing you would script bash for sometimes; it can be cleaner and more extensible.

In cloud there are other options though. You could happily use AWS SSM for anything you’d use ansible for (and SSM has way more options).

---
Tags: kubernetes, ansible, configuration-management, infrastructure-as-code, eks
---


# Question
Title: Issue in running docker container on ecs
I am trying to run container on ecs but there is one specific image which is not running and give me error. I can see in docker container ec2 that image is pulled and it tried to run but it gave following error

```
019ee43da7b91c68126e0d671" status="CREATED"
level=info time=2022-05-05T09:36:40Z msg="Container change also resulted in task change" desiredStatus="RUNNING" knownStatus="CREATED" task="cb091374b6ca45629c4f41bfed9c16fb" container="toxic-container" runtimeID="a6801c731cfa6ddc54ae42e0022d679cd12feab019ee43da7b91c68126e0d671"
level=info time=2022-05-05T09:36:40Z msg="Starting container" task="cb091374b6ca45629c4f41bfed9c16fb" container="toxic-container" runtimeID="a6801c731cfa6ddc54ae42e0022d679cd12feab019ee43da7b91c68126e0d671"
level=error time=2022-05-05T09:36:41Z msg="Error transitioning container" container="toxic-container" runtimeID="a6801c731cfa6ddc54ae42e0022d679cd12feab019ee43da7b91c68126e0d671" nextState="RUNNING" error="Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: \"/\": permission denied: unknown" task="cb091374b6ca45629c4f41bfed9c16fb"
level=info time=2022-05-05T09:36:41Z msg="Handling container change event" task="cb091374b6ca45629c4f41bfed9c16fb" container="toxic-container" runtimeID="a6801c731cfa6ddc54ae42e0022d679cd12feab019ee43da7b91c68126e0d671" status="RUNNING"
level=warn time=2022-05-05T09:36:41Z msg="Error starting/provisioning container[%s (Runtime ID: %s)];" task="cb091374b6ca45629c4f41bfed9c16fb" container="toxic-container" runtimeID="a6801c731cfa6ddc54ae42e0022d679cd12feab019ee43da7b91c68126e0d671" error="Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: \"/\": permission denied: unknown"

```

Steps to reproduce it

1. I created ECS cluster on amazon with select EC2 Linux + Networking
2. for Cluster name\* sample
3. select on-demand instance
4. EC2 instance type: t2.large
5. Number of instances\* 1
6. Key pair my key
7. create new vpc
8. security group used with ssh and 5000
9. select ecsInstanceRole Then click to create

On the task definition

1. Create new task definition
2. Ec2
3. Task definition name : server
4. Require capatibilities: Ec2
5. click Add Container a. server-container b. image: quay.io/codait/max-toxic-comment-classifier c. Memory Limit 4096 d. port mapping: host Port: 5000 , container port: 5000
6. Add

Now task created so I click to run task, and it started, then it pull image and I can see image is pulled, but when it runs it give me above error.

Docker image works perfectly on local system, and it is public image.

How can I fix it?

# Answer
Did you choose/select `ecsTaskExecutionRole`? When creating a new task definition. Cause it's a must. OR create a role manually for tasks that gives API requests permission to AWS services.

Also, give task execution role IAM (you may use the same one created before)

Update: I deployed your image with ECS EC2 and it's working fine... I'm not sure but I think you have issues using/defining roles...
> 1 votes

---
Tags: amazon-web-services, amazon-ec2, amazon-ecs
---


# Question
Title: Apex domain to point to an Openshift ROSA application
We have a ROSA (Openshift on AWS) cluster, working fine with all kinds of domains except one, which happens to be an apex of the Hosting Zone in our Route53. So, say, the domain is `example.com` and it's registered in AWS with the name servers - all well. I have created a CustomDomain in the Openshift cluster that works for all it's subdomains eg. `www.example.com`. This is thanks to a wildcard CNAME record that points all `*.example.com` queries to `zhfsrc.example-com.test.plvo.p1.openshiftapps.com` provided by the CustomDomain object:

```
apiVersion: managed.openshift.io/v1alpha1
kind: CustomDomain
metadata:

  name: example-com

spec:
  certificate:
    name: example-com-tls
    namespace: example
  domain: example.com
  scope: External
status:
  conditions:
...
    - lastProbeTime: '2022-04-13T16:11:33Z'
      lastTransitionTime: '2022-04-13T16:11:33Z'
      message: Custom Apps Domain (example.com) Is Ready
      reason: Ready
      status: 'True'
      type: Ready
  dnsRecord: '*.example-com.test.plvo.p1.openshiftapps.com.'
  endpoint: zhfsrc.example-com.test.plvo.p1.openshiftapps.com
  scope: ''
  state: Ready

```

Now, I am missing the A record and this breaks the deal. Restrictions found:

* the apex domain cannot be a CNAME
* the A record in Route53 cannot point to a CNAME
* there is (apparently) no resource the A record can be an alias for (tried the openshift LBs)
* CNAME flattening is not available in Route53

I see this as a most basic use case - a domain registered via AWS pointing to an Openshift application, yet neither RH nor AWS support were able to help so far.

# Answer
> 0 votes
The AWS support finally helped, it was kind of blurry between RH and Route53. So, the trick is to find your endpoint in the Hosting Zone managed by Openshift, in our case:

```
*.example-com.test.plvo.p1.openshiftapps.com

```

Note the Elastic Load Balancer it's pointing to (the "Value/Route traffic to" column). Then go back to the Hosting Zone in question and add an A record as an alias to the same ELB in its respective region.

* **record name:** example.com
* **record type:** A
* **route traffic to:** \[x\] Alias
* Alias to Application and Classic Load Balancer
* \[region of your ROSA cluster\]
* \[dualstack.the-ID-of-your-ELB.elb.amazonaws.com.\]

After 60 secs it's already propagated.

thanks AWS!

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


# Question
Title: How can I run apt-get update and apt-get upgrade commands automatically?
I have a docker container where I run a few commands as a root user each time it is created from an image. Is it possible to automate running these commands as a root administrator user each time my container is created?

```
# apt-get update

# apt-get upgrade

# apt-get install -y vim

```

# Answer
> 1 votes
Since you are using a ready-made Docker image, and want additional package(s) on top of it, writing a Dockerfile would be "automation" of the commands. Using this you can create a new image with what you want pre-installed.

Example `Dockerfile`:

```
FROM pimcore/pimcore:PHP7.4-apache

RUN apt-get update && apt-get upgrade && apt-get install -y vim

```

Then use the `docker build` command to build an image with a name (tag) that you want.

Example below creates image named `my-phpapache:7.4`, you can use a name that makes sense to you. This image will have `vim` installed.

```
docker build -t my-phpapache:7.4 .

```

Note the `.`, this should be run in the same directory as the `Dockerfile`.

You may find that using the `Dockerfile` to copy configuration into the image may eliminate the need to have `vim` installed in it.

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


# Question
Title: How to assign an ACL for each S3 Bucket in a tuple/list using Terraform?
I have a terraform file set to create a list of S3 buckets, and I was assigning acl to each bucket the old way:

```
resource "aws_s3_bucket" "this" {
    count = length(var.s3_bucket_names)
    bucket = var.s3_bucket_names[count.index]
    acl = var.acl
    tags = var.tags
}

```

However, I want to know how to do it using `aws_s3_bucket_acl` but I can't reference the bucket because it is a tuple and not a string. I've tried a lot of things but I've got nothing so far.

This is what I want to do:

```
resource "aws_s3_bucket_acl" "this_acl" {
    bucket = HERE I DON'T KNOW HOW TO REFERENCE A TUPLE OR LIST
    acl = var.acl
}

```

What should I do to reference a tuple since `aws_s3_bucket.this.*.id` doesn't work with a tuple/list?

Thank you in advance.

# Answer
I just found a solution, I've created "count" for every resource:

```
resource "aws_s3_bucket" "this" {
    count = length(var.s3_bucket_names)
    bucket = var.s3_bucket_names[count.index]
    tags = var.tags
}

resource "aws_s3_bucket_acl" "this_acl" {
    count = length(aws_s3_bucket.this)
    bucket = aws_s3_bucket.this[count.index].id
    acl = var.acl
}

```
> 2 votes

---
Tags: terraform, amazon-s3
---


# Question
Title: Terraform: Why is null_resource's remote-exec not connecting to aws_instance via SSH?
I've been going through answers to similar questions on this StackExchange and on StackOverflow and reading through documentations all day ...

Here's the .tf file I'm executing:

```
# defines the AWS provider
provider "aws" {
  # credentials path: ~/.aws/credentials
  profile = var.aws_profile
}
resource "aws_key_pair" "key_pair" {
  # variable's default value: "id_rsa"
  key_name   = var.aws_key_pair_name
  # variable's default value: public key of "id_rsa"
  public_key = var.aws_key_pair_public
}
resource "aws_security_group" "security_group" {
  ingress {
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    # variable's default value: "security-group-1"
    Name = var.aws_security_group_tags_name
  }
}
resource "aws_instance" "instance" {
  # variable's default value: ID of the Ubuntu AMI
  ami = var.aws_instance_ami
  # variable's default value: "t2.micro"
  instance_type = var.aws_instance_type
  associate_public_ip_address  = true
  key_name = aws_key_pair.key_pair.key_name
  vpc_security_group_ids = [aws_security_group.security_group.id]
  tags = {
    # variable's default value: "ec2-instance-1"
    Name = var.aws_instance_tags_name
  }
}
resource "null_resource" "instance" {
  provisioner "remote-exec" {
    connection  {
      type = "ssh"
      host = aws_instance.instance.public_ip
      # variable's default value: "ubuntu", Ubuntu AMI's default system user account
      user = var.aws_instance_user_name
      # variable's default value: "~/.ssh/id_rsa"
      # the path to the public key provided to aws_key_pair.key_pair
      private_key = file(var.aws_key_pair_private_path)
      timeout = "20s"
    }
    inline = ["echo 'remote-exec message'"]
  }
  provisioner "local-exec" {
    command = "echo 'local-exec message'"
  }
}

```

I tried executing it with the permissions of the private key's file set to 400 and 600. It's returning the following error in both cases:

```
aws_instance.instance (remote-exec): Connecting to remote host via SSH...
aws_instance.instance (remote-exec):   Host: 54.82.23.158
aws_instance.instance (remote-exec):   User: ubuntu
aws_instance.instance (remote-exec):   Password: false
aws_instance.instance (remote-exec):   Private key: true
aws_instance.instance (remote-exec):   Certificate: false
aws_instance.instance (remote-exec):   SSH Agent: true
aws_instance.instance (remote-exec):   Checking Host Key: false
aws_instance.instance (remote-exec):   Target Platform: unix
aws_instance.instance: Still creating... [1m0s elapsed]
╷
│ Error: remote-exec provisioner error
│
│   with aws_instance.instance,
│   on main.tf line 63, in resource "aws_instance" "instance":
│   63:   provisioner "remote-exec" {
│
│ timeout - last error: SSH authentication failed (ubuntu@54.82.23.158:22): ssh: handshake failed: ssh: unable to
│ authenticate, attempted methods [none publickey], no supported methods remain

```

This is despite of the fact that the following command connects to the EC2 instance successfully:

```
ubuntu:~/projects/course-1/project-1$ ssh -i "id_rsa" ubuntu@ec2-54-163-199-195.compute-1.amazonaws.com

```

What am I missing? Is there a better apprach?

# Answer
You need to change `remote-exec` syntax a bit. First, establish a connection to the remote server then execute with the provisioner as:

```
    resource "null_resource" "instance" {
      connection  {
        type = "ssh"
        host = aws_instance.instance.public_ip
        # variable's default value: "ubuntu", Ubuntu AMI's default system user account
        user = var.aws_instance_user_name
        # variable's default value: "~/.ssh/id_rsa"
        # the path to the public key provided to aws_key_pair.key_pair
        private_key = file(var.aws_key_pair_private_path)
        timeout = "20s"
      }
      provisioner "remote-exec" {
        inline = ["echo 'remote-exec message'"]
      }
      provisioner "local-exec" {
        command = "echo 'local-exec message'"
      }
    }

```

This should fix your problem. Thank you!
> 0 votes

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


# Question
Title: Make a readiness probe to fail when there is a newer version of the app being rolled out
# How to make a readiness probe fail when there is a newer version of the app available

Stack: Node.js, GKE

## Context

Clients are connected to pods via **websockets**. During a **rolling update**, clients that disconnect from the old pods can connect to either old pods or new pods. I want to minimize client disconnections and force them to **connect only to the newest version of the pods**. **Making sure that ONLY one disconnection/connection takes place is crucial**, I want to maximize the uptime of client connections, I cannot afford clients to connect/disconnect multiple times.

For this purpose I want to use the readinessProbe. I need to make it fail for old pods when a rolling update is taking place.

Recreate strategy cannot be used since the re-connection of all clients at once creates a big load on the system.

## Ideas

### 1. ConfigMap that holds the latest version of the app.

1. The current version of the app is passed as an env var and it is stored in memory.
2. The newest version of the app lives in a ConfigMap.
3. Health endpoint returns the `oldVersion` and `newVersion`.
4. Readiness probe GETs the /health and compares the two versions (`exec/curl`), *if not equal exit 1* and the probe fails.

Drawbacks:

* Configmaps can take some minutes to sync which is a lot in my case. Is there a way to accelerate it?

> the total delay from the moment when the ConfigMap is updated to the moment when new keys are projected to the Pod can be as long as the kubelet sync period + cache propagation delay

https://kubernetes.io/docs/concepts/configuration/configmap/

What happens during a rollback?

* Logic to update the config map again and have the probes failing. Helm will not do the trick (`helm upgrade --install`)

The purpose of this question is to find a way to do it in a timely manner. Do you have other ideas?

# Answer
If your pods start fast, perhaps use recreate strategy, that will make sure to terminate "old" pods and "recreate" new ones.

> All existing Pods are killed before new ones are created when `.spec.strategy.type==Recreate`.
> 0 votes

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


# Question
Title: K8S + HELM. Create a persistence volume for mysql database
I am using *K8S* with *Helm 3*.

I am also using *MYSQL 5.7* database.

How can I create *MYSQL* pod, that the database will persist (created on first time) after first time the pod is created, and even the pod is down and up again, the data won't be lost?

I am using `PersistentVolume` and `PersistentVolumeClaim`.

Here are the *YAML* files:

**Mysql pod:**

```
apiVersion: v1
kind: Pod
metadata:
  name: myproject-db
  namespace: {{ .Release.Namespace }}
  labels:
    name: myproject-db
    app: myproject-db
spec:
  hostname: myproject-db
  subdomain: {{ include "k8s.db.subdomain" . }}
  containers:
    - name: myproject-db
      image: mysql:5.7
      imagePullPolicy: IfNotPresent
      env:
        MYSQL_DATABASE: test
        MYSQL_ROOT_PASSWORD: 12345
      ports:
        - name: mysql
          protocol: TCP
          containerPort: 3306
      resources:
        requests:
          cpu: 200m
          memory: 500Mi
        limits:
          cpu: 500m
          memory: 600Mi
      volumeMounts:
        - name: mysql-persistence-storage
          mountPath: /var/lib/mysql
  volumes:
    - name: mysql-persistence-storage
      persistentVolumeClaim:
        claimName: mysql-pvc

```

**Persistent Volume:**

```
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
  labels:
    type: local
    name: mysql-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/mysql"

```

**Persistent Volume Claim:**

```
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  volumeMode: Filesystem
  volumeName: mysql-pv

```

Also, created a storage class. It is not used, but here it is:

**Storage Class:**

```
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: mysql-storage
provisioner: docker.io/hostpath
volumeBindingMode: WaitForFirstConsumer

```

after running:

Helm install myproject myproject/

The database is created, and can be used.

If I add records and stop and remove the database pod, I would like that the records will be kepts - no loss of db.

Instead, I see that the db data is lost when the MYSQL pod is restarted.

What can I do in order to use `helm install ...` or `helm upgrade` (it is important that the pod created by helm command) and only after first time it will create the database, and for the next times the database data won't be lost?

Thanks.

# Answer
> 1 votes
It seems that you are using the host file system for the persistent volume. Assuming that you have multiple worker nodes and the pod restarts on a different node, the data is “lost” (only exists in the node that it ran on previously).

Force the pod to run on 1 particular node and restart the pod. You’ll notice that the data is still there as it restarts on the same node as before.

---
Tags: kubernetes, helm, mysql, persistent-volumes
---


# Question
Title: Does Terraform provide a mechanism to find the provider version?
Other than reading `.terraform.lock.hcl` is there a mechanisms in Terraform to find the version of the providers I am using with the cli interface?

I don't see the version when I run `terraform providers` or the ability to add a `-v` flag (or another flag) under `terraform providers --help`

# Answer
You can find the version of your providers with `terraform version`

```
❯ terraform version
Terraform v1.1.9
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v3.75.1

```

## With `jq`

```
❯ terraform version -json | jq .provider_selections
{
  "registry.terraform.io/hashicorp/aws": "3.75.1"
}

```

terraform version -json | jq .provider\_selections

I opened a UX Improvement case on GitHub #31048
> 0 votes

---
Tags: terraform, versioning
---


# Question
Title: How do I upgrade or pin a Terraform Provider?
This is a follow-up to The provider hashicorp/aws does not support resource type "aws\_internet\_gateway\_attachment".

The crux of it is, I'm using 3.75.1 of the AWS provider, and I need to upgrade. How do I do that?

I got the version by reading the `.terraform.lock.hcl`

```
provider "registry.terraform.io/hashicorp/aws" {
  version     = "3.75.1"

```

# Answer
# Upgrading to the newest version

You can upgrade the provider with

```
terraform init -upgrade

```

So long as you don't have the version specified anywhere in a `required_providers` block.

# Pinning with a `required_providers` block

You can pin or specify any arbitrary version constraint with a `required_providers` block, like this.

```
terraform {
  required_providers {
    aws = {
      source = "registry.terraform.io/hashicorp/aws"
      version = "4.14.0"
    }
  }
}
provider "aws" {
  region = "us-east-1"
}

```

# Terraform pre 0.13

Prior to Terraform version 0.13, you could specify your version in the provider block,

```
provider "aws" {
  version = "4.14.0"
  region = "us-east-1"
}

```

---

Find the official docs at,
> 1 votes

---
Tags: terraform, versioning
---


# Question
Title: The provider hashicorp/aws does not support resource type "aws_internet_gateway_attachment"
Why do I get this error with Terraform,

> The provider hashicorp/aws does not support resource type "aws\_internet\_gateway\_attachment".

You can see the resource `aws_internet_gateway_attachment` defined in the docs. The full error is,

```
│ Error: Invalid resource type
│
│   on main.tf line 26, in resource "aws_internet_gateway_attachment" "example":
│   26: resource "aws_internet_gateway_attachment" "example" {
│
│ The provider hashicorp/aws does not support resource type "aws_internet_gateway_attachment".
╵

```

this is the hdl I'm using

```
resource "aws_internet_gateway_attachment" "example" {
  internet_gateway_id = aws_internet_gateway.gw.id
  vpc_id              = aws_vpc.main.id
}

```

---

I'm using version 3.75.1 of the AWS provider.

# Answer
The terraform docs default to the lastest, version. The doc page you're looking at is,

> https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet\_gateway\_attachment#attributes-reference

What you want to do is replace that `latest` with the version you're using, in this case `3.75.1`. Like this,

> https://registry.terraform.io/providers/hashicorp/aws/3.75.1/docs/resources/internet\_gateway\_attachment#attributes-reference

That brings up a 404,

> This documentation page doesn't exist for version 3.75.1 of the aws provider.

Which basically means you must upgrade the Terraform provider.
> 3 votes

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


# Question
Title: Cloud-config in Terraform does not work, nothing seems to happen and it fails silently
I'm currently provisioning a machine with Cloud Config in `user_data` (I've also tried `user_data_base64`). When I run my command in Terraform I have,

```
resource "aws_instance" "web" {
    user_data_base64 = filebase64("${path.module}/scripts/web-init-script.yml")

```

However, nothing happens. It silently fails. What's the problem? The contents of `web-init.script.yml` are,

```
❯ cat scripts/db-init-script.sh
#cloud-config
package_update: true
package_upgrade: true

fqdn: db.acme.com
prefer_fqdn_over_hostname: true
hostname: db

packages:
    - podman

```

# Answer
# Failure to Merge - YAML whitespace

This turned out to be because of whitespace. You can confirm this by sshing to the machine and running

```
sudo grep WARNING /var/log/cloud-init.log

```

Which should return this,

```
util.py[WARNING]: Failed loading yaml blob. Invalid format at line 11 column 1: "while scanning for the next token
util.py[WARNING]: Failed at merging in cloud config part from part-001

```

Basically what happens is this,

1. You upload the `user_data` to the providers instance's metadata.
2. The client you're provisioning launches `cloud-init`.
3. That downloads the `user_data` from the instance's metadata at `http://169.254.169.254/`
4. It sees the `#cloud-config` on line one of your `user_data`
5. You merge your own cloud\_config with the downloaded `user_data`
6. The merge-algorithm doesn't normalize for whitespace, so the yaml is invalid.
7. The merge-algorithm returns a blank cloud-config.

You can verify this by trying to re-run `cloud-init init` which will produce something like this,

```
2022-05-16 04:50:04,351 - util.py[WARNING]: Failed loading yaml blob. Invalid format at line 11 column 1: "while scanning for the next token
found character '\t' that cannot start any token
  in "<unicode string>", line 11, column 1:
        - podman
    ^"
2022-05-16 04:50:04,351 - util.py[WARNING]: Failed at merging in cloud config part from part-001

```

## Full Log

```
__init__.py[DEBUG]: {'MIME-Version': '1.0', 'Content-Type': 'text/cloud-config', 'Content-Disposition': 'attachment; filename="part-001"'}
__init__.py[DEBUG]: Calling handler CloudConfigPartHandler: [['text/cloud-config', 'text/cloud-config-jsonp']] (text/cloud-config, part-001, 3) with frequency once-per-instance
util.py[DEBUG]: Attempting to load yaml from string of length 252 with allowed root types (<class 'dict'>,)
util.py[WARNING]: Failed loading yaml blob. Invalid format at line 11 column 1: "while scanning for the next token
found character '\t' that cannot start any token
  in "<unicode string>", line 11, column 1:
        - podman
    ^"
util.py[WARNING]: Failed at merging in cloud config part from part-001
util.py[DEBUG]: Failed at merging in cloud config part from part-001
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/cloudinit/handlers/cloud_config.py", line 140, in handle_part
    self._merge_part(payload, headers)
  File "/usr/lib/python3/dist-packages/cloudinit/handlers/cloud_config.py", line 116, in _merge_part
    (payload_yaml, my_mergers) = self._extract_mergers(payload, headers)
  File "/usr/lib/python3/dist-packages/cloudinit/handlers/cloud_config.py", line 95, in _extract_mergers
    mergers_yaml = mergers.dict_extract_mergers(payload_yaml)
  File "/usr/lib/python3/dist-packages/cloudinit/mergers/__init__.py", line 79, in dict_extract_mergers
    raw_mergers = config.pop('merge_how', None)
AttributeError: 'NoneType' object has no attribute 'pop'
__init__.py[DEBUG]: Calling handler CloudConfigPartHandler: [['text/cloud-config', 'text/cloud-config-jsonp']] (__end__, None, 3) with frequency once-per-instance
util.py[DEBUG]: Writing to /var/lib/cloud/instances/i-0804054440b55ca17/cloud-config.txt - wb: [600] 26 bytes

```
> 0 votes

---
Tags: terraform, yaml, cloud-init
---


# Question
Title: How do I create a Docker image from a container without configuration changes?
I am aware of two ways of creating Docker images:

1. Build the image using a Dockerfile
2. Use `docker commit <container_id>` against a running container with changes.

I find changing a Dockerfile each time I need image changes to be awfully inconvenient. Instead I have taken to launching ephemeral containers with `docker run`, installing packages I need on the fly with sudo, then committing the image.

I didn't realize however there is a footgun involved in this approach, especially if you frequently use and switch up `docker run` hacks. I launch containers with changing bind mounts, environment variables, differing networks, etc. A lot of that seems to be considered part of the configuration of the container, and is committed in `docker commit` alongside actual filesystem changes.

For example if you do:

```
docker run --env FOO=BAR --name container_name ubuntu:focal
docker commit container_name new_image
docker run -it new_image
echo $FOO

```

You will see that the env variable FOO is now a part of new\_image.

This creates some awfully confusing situations, as I consider arguments to `docker run` to be as ephemeral as the container it creates. I am only concerned about persisting package installs.

> I would like to commit *just* the actual image, just the file system changes. Is there any way to do that?

# Answer
> 1 votes
You could try giving `docker commit --change` a try.

```
docker run --env FOO=BAR <image>
docker commit --change "ENV FOO=SETVALUE" <container_from_image> <new_image_tagged_from_state_of_container>

```

Please note that docker's engine specifies that *"\[If the operator\] names an environment variable without specifying a value, then the current value of the named variable is propagated into the container’s environment"* so you'll need to set the environment variable to something such as `SETVALUE` an environment variable without specifying a value, the current value of the named variable on the host is propagated into the container's environment

# Answer
> 0 votes
Share us an example of your recurring "image changes". I think your problem is not with docker, is with the architecture of your application.

* Data changes should be handled using a database not the file system.
* Source code changes, should be managed with a git repository and the respective new build, generating a new image version ready to be deployed
* Infrastructure changes should be ... **That's what Docker was created for.** You should modify the Dockerfile, push the changes, build a new image, etc
* Configurations should be managed with environment variables manually injected at docker run or using some external service like consul, configurator, etc
* If your application needs to upload or download files like images, reports, etc, you should use a specialized service like aws s3, gcp Filestore, some open source, etc

As you can see, you don't need a huge native backup with docker commit.

# Answer
> 0 votes
# Buildah

> This creates some awfully confusing situations, as I consider arguments to docker run to be as ephemeral as the container it creates. I am only concerned about persisting package installs.

Sure does. Don't use docker. =) Docker is just one method of creating an image. It blurs the line between and online (hot container) and offline build process. Instead try `buildah`, which works with any shell. No dockerfile needed, also runs rootless. Try the below with `buildah unshare ./image.sh`

```
#!/bin/bash
# Call this script image.sh
# Invoke as regular user with `buildah unshare ./image.sh`
ctr=$(buildah from alpine:3)
mnt=$(buildah mount "$ctr")

echo "Created offline container $ctr"
echo "Got mount $mnt"

# write/copy/move directly into $mnt
echo "Write directly into mount" > "$mnt/foo.txt"

temp=$(mktemp)
echo "Created temp $temp"
echo foo > "$temp"
mv "$temp" "$mnt/bar"

echo "No container running"

buildah run "$ctr" /bin/sh <<-EOF
  echo "Hello from inside container.";
  apk update;
  apk add podman;
  echo 42 > baz;
EOF

buildah config                     \
  --author "Joe Doe <foo@bar.com>" \
  --label "apples=oranges"         \
  --env "foo=bar"                  \
  "$ctr";

buildah commit "$ctr" mynewimage

```

You can see what that includes

```
podman run -i mynewimage /bin/sh <<-"EOF"
  echo -e "\nfoo:"
  cat foo

  echo -e "\nbar:"
  cat bar

  echo -e "\nbaz:"
  cat baz

  echo -e "\nenv"
  env
EOF

```

---
Tags: docker, dockerfile
---


# Question
Title: Sprint planning: dots within the daily capacity of a developer are ignored
When I define the daily capacity of a developer during a sprint and this value contains a dot (e.g. 2.5 hours), after I save the changes the developer will have a daily capacity of 25 hours.

Daily capacity of the developer before saving the changes:

Daily capacity of the developer after saving the changes:

When I use a comma instead of the dot, this problem won't occur.

Is there any way to change this behavior in Azure DevOps, so that the dot can be used instead of the comma?

# Answer
An easy way to override the settings from Azure DevOps is to install the Chrome extension "Locale Switcher"
> 0 votes

---
Tags: azure-devops
---


title: Difference between chroot and Docker

text:
# Question
Title: Difference between chroot and Docker
I don't understand the difference between docker and chroot. Yes its nice in terms of the packaging the registry. But somehow I get the feeling its just chroot with extra bells and whistles.

I know I'm missing something. It'd would be great to know how they are different and the need of docker if chroot could do something similar.

I couldn't find this Chroot Vs Docker clear enough either.

# Answer
Well, the extra bells and whistles is called process isolation, a container gets its own namespace from the host kernel, that means the program in the container can't try to read kernel memory or eat more RAM than allowed.

It also isolate network stacks, so two process can listen on port 8080 for exemple, you'll have to handle the routing at host level, there's no magic here, but this allow handling the routing at one place and avoid modifying the process configuration to listen to a free port.

Secondly a chroot is still read/write, any change is permanent, a docker container using `aufs` will start from a clean filesystem each time you launch the container (changes are kept if you stop/start it IIRC).

So while a container may be thought of as `process namespace` \+ `chroot`, the reality is a little more complex.
> 14 votes

# Answer
Yes, there absolutely is more to it than `chroot` to the point that they have little to nothing in common.

* A standardized script file format including semantics relating to the task a hand
* Images (including anonymous in-between images), caching, naming, downloading etc. including powerful management (`docker image prune` ...)
* Containers (including their own temporary file systems, naming, being able to `docker exec` into them etc.)
* Process management (`docker container ...`)
* Networking with just a simple option, including intra-docker-container-networking etc.
* Volumes (including special managed volumes)
* `docker-compose` or swarm as low-profile upgrades to much more.
* The large zoo of other solutions based on dockerized containers (OpenShift etc.).
> 8 votes

# Answer
# `chroot` is not a security measure

Though some people mistakenly think it is, it isn't. From `man 2 chroot`,

> This call **changes an ingredient in the pathname resolution process and does nothing else.** In particular, it is not intended to be used for any kind of security purpose, neither to fully sandbox a process nor to restrict filesystem system calls. In the past, `chroot()` has been used by daemons to restrict themselves prior to passing paths supplied by untrusted users to system calls such as `open(2)`. However, if a folder is moved out of the chroot directory, an attacker can exploit that to get out of the chroot directory as well. The easiest way to do that is to `chdir(2)` to the to-be-moved directory, wait for it to be moved out, then open a path like ../../../etc/passwd.
>
> A slightly trickier variation also works under some circumstances if chdir(2) is not permitted. If a daemon allows a "chroot directory" to be specified, that usually means that if you want to prevent remote users from accessing files outside the `chroot` directory, you must ensure that folders are never moved out of it.
>
> This call does not change the current working directory, so that after the call '.' can be outside the tree rooted at '/'. In particular, the superuser can escape from a "chroot jail" by doing:
>
> ```
> mkdir foo; chroot foo; cd ..
>
> ```
>
> This call does not close open file descriptors, and such file descriptors may allow access to files outside the chroot tree.

# Namespaces

Namespaces are a security feature. Whereas chroot does not provide file system isolation, namespaces do precisely that.
> 1 votes

---
Tags: docker, linux, containers
---


# Question
Title: Snapshot or Saving Prometheus Data for Performance testing and comparison
I have an application and system that exposes its resource metrics to Prometheus and Grafana that I want to do performance testing on. I want to be able to conduct a test, capture the metrics on CPU, Memory, File I/O, etc, for a test run, and save them for comparison against another test run. I'll be running multiple tests at different times with different configurations but the resource metrics will be standardized.

For Example, for two 5 minute tests, Comparing CPU:

* Test 1 - 0:00-5:00
    + CPU Graph
* Test 2 - 0:00-5:00
    + CPU Graph

And then Comparing Memory:

* Test 1 - 0:00-5:00
    + Mem Usage Graph
* Test 2 - 0:00-5:00
    + Mem Usage Graph

Is there a way to save or record these metrics for A/B comparison using Prometheus and Grafana? Or would I be forcing these tools too hard to do something that they really aren't designed to do? If so, is there a better way/tool to capture and compare the data I'm looking for this type of performance testing?

# Answer
Grafana has option for directly pointing certain timeframe. https://grafana.com/docs/grafana/latest/dashboards/time-range-controls/

Save start and end time of your test OR test use fixed test duration added to startime to get endtime(for similar size of images) and compare exactly same grafana view from different time.

E.g.

Test1 is executed 1.12.2022 12:45:02 - 1.12.2022 12:47:02

Test2 is executed 5.12.2022 00:25:02 - 5.12.2022 00:27:02

Then you get two url ending for exactly same grafana view. It makes possible comparison, but you need to have two browser instances open in parallel.
> 1 votes

---
Tags: testing, prometheus, grafana, performance
---


# Question
Title: AKS Network Policy - cannot deny traffic to namespace
I am trying to implement Network Policies in my test Azure Kubernetes cluster, but I cannot get them to work. I have two namespaces - default and nginx (and others as well, but they shouldn't be affecting the NP).

I have an nginx deployment in each ns that displays a webpage with some text on '/'. (I have modified the pages slightly so I can recognize which one I'm hitting). I also have a ClusterIP service for each deployment. I deployed a Deny All Network Policy in the nginx namespace that targets all pods inside. However, when I open a shell inside the nginx pod in the default namespace and I do a curl http://servicename.namespace.svc:serviceport (which resolves to the service inside the nginx namespace) I can access the pod despite the Network Policy rule.

Here are my manifests:

* nginx in the nginx namespace:

```
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: svet-nginx-deployment
      namespace: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      replicas: 1
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: <azurecr>/samples/nginx
            ports:
            - containerPort: 80
            volumeMounts:
            - name: config-volume
              mountPath: /usr/share/nginx/html
          volumes:
          - name: config-volume
            configMap:
              name: svet-config

```
* ClusterIP service in the nginx namespace:

```
apiVersion: v1
kind: Service
metadata:
  name: ingress2
  namespace: nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

```
* Network Policy in the nginx namespace

I got this one from github, but I also tested with Default deny all ingress traffic from the official kubernetes documentation

```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: nginx
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress: []

```
* nginx in the default namespace:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: svet-nginx-deployment
  namespace: default
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: <azurecr>.azurecr.io/samples/nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config-volume
          mountPath: /usr/share/nginx/html
      volumes:
      - name: config-volume
        configMap:
          name: svet-config

```
* ClusterIP service in the default namespace:

```
apiVersion: v1
kind: Service
metadata:
  name: ingress1
  namespace: default
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

```

*Please ignore the bad naming - this is only a training environment*

I have tried many different iterations of the Network Policy starting with more complex and moving to the simplest denyall policy that I have pasted, but nothing seems to be working. I have enabled Azure CNI as required.

Am I missing something?

# Answer
If anyone else has the same issue, please double-check your AKS configuration in Azure and make sure that the Network policy filed in the Networking settings does NOT display None. It should say either Azure or Calico.

My cluster was created with terraform and even though I had added network\_plugin = "azure", I had missed the network\_policy = "azure" field which meant that Network Policies would not be applied.

Also, this setting can only be enabled when creating a new cluster. You cannot enabled it on an existing one.
> 1 votes

---
Tags: kubernetes, azure, azure-kubernetes-service
---


# Question
Title: What does the ASCII art on the Amazon Linux 2 AMI MOTD mean?
When logging in to an Amazon Linux EC2 instance, one is greeted by the following MOTD:

What does this ASCII art try to convey?

# Answer
> 5 votes
Just assume part of the ASCII-art chars have been made invisible, whereas if you would in-hide them all it would look (more or less) like so:

```
 ____   ____   ___
| ___| /  __| /_  )
| _|   | (     / /
|____| \____| /___|

```

I trust it’s clear then what the answer to your question actually is: `**EC2**` … Get it now?

---
Tags: amazon-web-services, amazon-ec2
---


# Question
Title: k3s: The connection to the server localhost:8080 was refused - did you specify the right host or port?
When I run any `kubectl` commands, I'm getting

> The connection to the server localhost:8080 was refused - did you specify the right host or port?

# Answer
This problem is likely caused by a bad `~/.kube/config` perhaps you have a file from a different kubernetes install (minikube) or an older k3s. If the server is local you can fix this by running these commands,

```
mkdir ~/.kube
sudo k3s kubectl config view --raw | tee ~/.kube/config
chmod 600 ~/.kube/config

```

The contents of `~/.kube/config` need to have the same information as `/etc/rancher/k3s/k3s.yaml` when the server was started (the keys, ip, and ports).

---

Note in order to tell k3s to use this config file you'll want to configure `KUBECONFIG`.

```
export KUBECONFIG=~/.kube/config

```

You should persist this by having it set in `~/.profile` or `~/.bashrc`
> 7 votes

---
Tags: kubernetes, k3s
---