# Question
Title: How does dependency management for Node.js differ from Maven?
Strange enough node.js unlikely maven installs the packages the software needs inside the project directory.

Is there a way to introduce a central repository which also caches different versions of components and would allow to pull them on build like we know it from other ecosystems?

# Answer
> Strange enough node.js unlikely maven installs the packages the software needs inside the project directory.

I don't see fundamental differences between npm on node.js and Maven. In both cases, the dependencies finally end up in the project directory (npm: `/node_modules`, Maven: `/target`). Otherwise, you cannot continue building the software. (When you run the build system to create the final artifact, it needs the dependencies.)

In addition, both have a global cache to avoid downloading already fetched dependencies: In Maven, the default cache directory is `~/.m2` (on Linux and MacOS). For npm, it is `~/.npm`.

> Is there a way to introduce a central repository which also caches different versions of components and would allow to pull them on build like we know it from other ecosystems?

If the system cache is not enough and you do not want to depend completely on the public repository (npm: registry.npmjs.org, Maven: Maven Central), you can run your own mirror. For instance, if you want to be able to rebuild the software even if the public repository is down.

In my previous job, we used Nexus as a caching proxy and local registry (for hosting code that is only accessible within your organization). It supports both npm (see documentation) and Maven (see documentation). (There are other tools, but the point is that both ecosystems can be handled by one tool.)

Of course, there are differences between Maven and npm. For instance, Maven is also a full build system, whereas the scope of npm is primarily dependency management. Maven also defines conventions to structure a Java project ("The Maven Way"). But when looking only at the dependency aspect, package managers for Node.js like npm are conceptually not so different from Maven.
> 6 votes

# Answer
In 2022, pnpm:https://pnpm.io/ is very similar to maven now. Pnpm will not copy files to node\_modules, instead creating hardlink.
> 0 votes

---
Tags: node.js
---


# Question
Title: Run docker-in-docker container alongside Jenkins agent
I'm looking for a way to run a Docker-in-Docker (dind) container alongside my Jenkins agent nodes using the Jenkins Kubernetes Plugin configured by Jenkins Configuration-as-Code (JCasC).

I'm currently running a plain agent node, that has all my tools installed. Including the Docker client. But no server/daemon running. My idea was now to add another container, that is running the Docker daemon. Both containers share the same working directory, so they operate on the same data.

Why having it running as two containers? The Docker daemon needs privileged access. And I want to restrict it as much as possible.

First problem that I encountered was, that Jenkins is not *killing the pod* when its finished building, but just ends the agent process. Now with another container running, the pod stays alive. I *fixed* this by writing a file to another shared volume when the agent pod stops, which in turn is read by the dind pod and exits when the file is present.

Here's an excerpt from my current Pod config:

```
apiVersion: "v1"
kind: "Pod"
spec:
  serviceAccountName: jenkins-agent
  containers:
  - image: "jenkins-jnlp-image"
    command: [ "/bin/sh", "-c" ]
    args:
    - |
      trap 'touch /usr/share/pod/done' EXIT
      /entrypoint.sh
    name: "jnlp"
    env:
    - name: DOCKER_HOST
      value: tcp://localhost:2375
    securityContext:
      privileged: false
    tty: true
    volumeMounts:
    - mountPath: "/home/jenkins/agent"
      name: "workspace-volume"
      readOnly: false
    - mountPath: /usr/share/pod
      name: tmp-pod
    workingDir: "/home/jenkins/agent"
  - image: "dind-image"
    name: "dind"
    command: [ "/bin/sh", "-c" ]
    args:
      - |
        dockerd-entrypoint.sh &
        while ! test -f /usr/share/pod/done; do
        echo 'Waiting for the jnlp to finish...'
        sleep 5
        done
        echo "Agent pod finished, exiting"
        exit 0
    securityContext:
      privileged: true
    tty: false
    volumeMounts:
    - mountPath: "/home/jenkins/agent"
      name: "workspace-volume"
      readOnly: false
    - mountPath: /usr/share/pod
      name: tmp-pod
    workingDir: "/home/jenkins/agent"
  volumes:
    - emptyDir:
        medium: ""
      name: "workspace-volume"
    - emptyDir: {}
      name: tmp-pod

```

Is this the deigned way of doing this? Is there any better?

Bonus question: I install from the official Helm chart. I could not find a good way to add another container there yet, without overwriting the whole pod template. Does anyone know of a way? If not I would probably create a PR to add that as a feature.

Thanks in advance!

# Answer
I wrote about Jenkins Docker in Docker Agent which you may find useful.

The article answers your questions in detail.

I'll answer them shortly here as well:

> Why having it running as two containers?

The first one is the container with Docker client. And it’s basically Jenkins agent, because it extends jenkins/jnlp-agent-docker base image. The second one is the container with Docker daemon inside.

> I install from the official Helm chart. I could not find a good way to add another container there yet, without overwriting the whole pod template.

You need to put a reference to docker in docker agent in `additionalAgents` key in helm chart `values.yaml`. See the example of Docker in Docker agent configuration.
> 1 votes

---
Tags: kubernetes, jenkins, kubernetes-helm, docker-in-docker
---


# Question
Title: Ansible jinja2 if/elif/else construct not working anymore
I am using a jinja2 template for creating several files. Those differ a bit dependent on a set variable.

Here's the code:

```
{% if production_env == "prod" or "stage" %}
  password: "{{ group_token }}"
  username: usernamedoesntmatterhere
{% elif production_env == "dev" %}
  password: "{{ mytoken }}"
  username: "{{ mytokenname }}"
{% else %}
    NONE
{% endif %}

```

As you can see when `production_env` is set to `dev` it should template the second block. It seems that my elif condition is not working anymore. I used a debug task to get output which variable is set and this is correctly set to `dev` Ansible renders the first block even if `dev` is set correctly.

That worked fine for months, not sure why it doesn't now.

I already ditched the `elif` block and set it to `else`, even this is not working.

Any hints?

Thanks

# Answer
> 0 votes
Fix the condition

```
{% if production_env == "prod" or
      production_env == "stage" %}
  password: "{{ group_token }}"
  username: usernamedoesntmatterhere
{% elif production_env == "dev" %}
  password: "{{ mytoken }}"
  username: "{{ mytokenname }}"
{% else %}
    NONE
{% endif %}

```

---
Tags: ansible
---


# Question
Title: cosmosdb_account virtual_network_rule for_each
I'm trying to create a set of subnet rules for a cosmosdb account.

I've tried a dynamic and a for\_each on the resource and I get the same error each time - am I going about this the wrong way?

Currently trying this:

```
resource "azurerm_cosmosdb_account" "db" {
  name                = local.name
  location            = var.location
  resource_group_name = var.resource_group_name

  offer_type       = "Standard" #(Required) Specifies the Offer Type to use for this CosmosDB Account - currently this can only be set to Standard.
  enable_free_tier = var.enable_free_tier
  kind             = var.kind

  identity {
    type = "SystemAssigned"
  }

  ip_range_filter = join(",", local.network_rules.ip_rules)

  dynamic "virtual_network_rule" {
    for_each = var.virtual_network_subnet_ids
    content {
      id = each.value
    }
  }
}

```

Currently getting:

```
Error: each.value cannot be used in this context
│
│   on .terraform/modules/azurerm_cosmosdb_account/azurerm_cosmosdb_account/main.tf line 27, in resource "azurerm_cosmosdb_account" "db":
│   27:       id = each.value
│
│ A reference to "each.value" has been used in a context in which it
│ unavailable, such as when the configuration no longer contains the value in
│ its "for_each" expression. Remove this reference to each.value in your
│ configuration to work around this error.
╵

```

# Answer
> 1 votes
A dynamic block does not use the `each` keyword, but the value of the `iterator` argument instead. If omitted, it will use the name of the dynamic block instead. Or as the documentation states it:

> The `iterator` argument (optional) sets the name of a temporary variable that represents the current element of the complex value. If omitted, the name of the variable defaults to the label of the `dynamic` block.

It's generally fine to omit the iterator argument and just go with the (what should be a) unique name of the block. In your case, replace `each.value` with `virtual_network_rule.value`, so you get:

```
dynamic "virtual_network_rule" {
  for_each = var.virtual_network_subnet_ids

  content {
    id = virtual_network_rule.value
  }
}

```

If you do want to use the `iterator` argument, it would look something like this:

```
dynamic "virtual_network_rule" {
  for_each = var.virtual_network_subnet_ids
  iterator = "rule"

  content {
    id = rule.value
  }
}

```

---
Tags: terraform, azure
---


# Question
Title: How to use same terraform code for both kubernetes clusters Oracle (OKE) and AWS (EKS)?
I want to use same terraform code for both kubernetes clusters oracle (OKE) and AWS (EKS) and install the argocd helm chart on it, I given my code below for your reference, now the problem I am facing now, if I set k8s\_cluster\_type to "eks", so everything works fine but when I set the k8s\_cluster\_type to "oke", it fails with given below error,

I get this error:-

```
│ Error: error reading EKS Cluster (oh-appb-01): couldn't find resource
│
│   with data.aws_eks_cluster.eks,
│   on main.tf line 137, in data "aws_eks_cluster" "eks":
│  137: data "aws_eks_cluster" "eks" {
│

```

What I want to do:-

In case if I give eks\_cluster\_name (dummy\_cluster\_name) or eks cluster doesn't exist, still this code should run as same like oke, because if I assign dummy\_name oke cluster or oke cluster doens't exist and input variable k8s\_cluster\_type to "eks" this terraform runs successfully, Could you suggest, how can I use same terraform for both kubernetes cluster to install argocd helm chart

```
locals {
  argocd_ns = "argocd"

  kubeconfig_str = var.k8s_cluster_type == "oke" ? data.oci_containerengine_cluster_kube_config.k8s.content : data.template_file.temp_kubeconfig_eks.rendered
  kubeconfig = yamldecode( local.kubeconfig_str )

  exec_cli = var.k8s_cluster_type == "oke"? "oci" : "aws"

  cluster_cert = var.k8s_cluster_type == "oke" ? base64decode(local.kubeconfig["clusters"][0]["cluster"]["certificate-authority-data"]) : base64decode(data.aws_eks_cluster.eks.certificate_authority[0].data)
  cluster_endpoint = var.k8s_cluster_type == "oke" ? local.kubeconfig["clusters"][0]["cluster"]["server"] : data.aws_eks_cluster.eks.endpoint

  exec_args_oke = [
    local.kubeconfig["users"][0]["user"]["exec"]["args"][0],
    local.kubeconfig["users"][0]["user"]["exec"]["args"][1],
    local.kubeconfig["users"][0]["user"]["exec"]["args"][2],
    local.kubeconfig["users"][0]["user"]["exec"]["args"][3],
    local.kubeconfig["users"][0]["user"]["exec"]["args"][4],
    local.kubeconfig["users"][0]["user"]["exec"]["args"][5],
    local.kubeconfig["users"][0]["user"]["exec"]["args"][6]
  ]

  exec_args_eks = ["eks", "get-token", "--cluster-name", var.eks_cluster_name]
  exec_args = var.k8s_cluster_type == "oke" ? local.exec_args_oke : local.exec_args_eks

}

data "oci_containerengine_cluster_kube_config" "k8s" {
  #count = var.k8s_cluster_type == "oke" ? 1 : 0
  cluster_id = var.k8s_cluster_id
}

resource "local_file" "temp_kubeconfig" {
  count = var.k8s_cluster_type == "oke" ? 1 : 0
  content  = local.kubeconfig_str
  filename = "${path.module}/kubeconfig_temp"
}

resource "local_file" "temp_kubeconfig_eks" {
  count = var.k8s_cluster_type == "oke" ? 0 : 1
  content  = data.template_file.temp_kubeconfig_eks.rendered
  filename = "${path.module}/kubeconfig_temp"
}

resource "kubernetes_namespace" "argocd" {
  metadata {
    name = local.argocd_ns
  }
}

resource "kubernetes_secret" "root_repo" {
  depends_on = [kubernetes_namespace.argocd]
  metadata {
    name = var.argocd_root_repo.name
    namespace = local.argocd_ns
    labels = {
      "argocd.argoproj.io/secret-type" = "repository"
    }
  }
  data = {
    url = var.argocd_root_repo.url
    name = var.argocd_root_repo.name
    password = var.argocd_root_repo_token
    username = var.argocd_root_repo.name

  }
}

data "template_file" "argocd-helm-values-override" {
  template = file("${path.module}/templates/argocd-helm-values-override.tpl")
  vars = {
    argocd_ns = local.argocd_ns
    repo_url = var.argocd_root_repo.url
    repo_path = var.argocd_root_repo.path
    repo_revision = var.argocd_root_repo.revision
  }
}

resource "helm_release" "argocd" {
  depends_on = [kubernetes_namespace.argocd, kubernetes_secret.root_repo ]
  version    = var.argocd_release.chart_version
  name       = var.argocd_release.release_name
  chart      = var.argocd_release.chart_name
  repository = var.argocd_release.chart_repo
  namespace  = local.argocd_ns
  values = [
    data.template_file.argocd-helm-values-override.rendered
  ]
}

data "template_file" "temp_kubeconfig_eks" {
  count = var.k8s_cluster_type == "oke" ? 0 : 1
  template = file("${path.module}/templates/kubeconfig_eks.tpl")
  vars = {
    cluster_url = data.aws_eks_cluster.eks.endpoint
    cluster_region = var.region
    cluster_cert_authority_data = data.aws_eks_cluster.eks.certificate_authority.0.data
    cluster_name = var.eks_cluster_name
  }
}

provider "kubernetes" {
  cluster_ca_certificate = local.cluster_cert
  host                   = local.cluster_endpoint
  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = local.exec_cli
    args        = local.exec_args
  }
}
provider "helm" {
  kubernetes {
    cluster_ca_certificate = local.cluster_cert
    host                   = local.cluster_endpoint
    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      command     = local.exec_cli
      args        = local.exec_args
    }
  }
}

data "aws_eks_cluster" "eks" {
  #count = var.k8s_cluster_type == "oke" ? 0 : 1
  name = var.eks_cluster_name
}

data "aws_eks_cluster_auth" "eks" {
  #count = var.k8s_cluster_type == "oke" ? 0 : 1
  name = var.eks_cluster_name
}

```

\*.tfvars file:-

```
8s_cluster_id ="ocid1.cluster.oc1.xxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
k8s_cluster_type = "oke"

argocd_root_repo = {
  name = "argocd-xxxx-xxxx-config",
  url = "https://github.com/xxxxx/xxxx/argocd-xxxx-xxxx-config",
  path = "clusters/localsand1/apps",
  revision = "master"
}

region = "us-east-1"
eks_cluster_name = "oh-appb-01"

```

# Answer
You have commented out the `count` check of the `aws_eks_cluster.eks` data source that would make the data source conditional, depending on the `k8s_cluster_type` setting. Uncommenting the count argument should make it skip the data source and not complain about it not being found.

```
data "aws_eks_cluster" "eks" {
  count = var.k8s_cluster_type == "oke" ? 0 : 1
  name  = var.eks_cluster_name
}

```
> 0 votes

---
Tags: kubernetes, terraform, eks, kubernetes-helm, terragrunt
---


# Question
Title: "ipv6_cidr_block": all of `ipv6_cidr_block,ipv6_ipam_pool_id` must be specified
**Usage**: import

**Version**: Terraform v1.1.9

* provider registry.terraform.io/hashicorp/aws v4.11.0

I've something like this defined:

```
  assign_generated_ipv6_cidr_block = "true"
  cidr_block                       = "10.0.0.0/16"
  enable_dns_hostnames             = "true"
  enable_dns_support               = "true"
  instance_tenancy                 = "default"
  ipv6_cidr_block                      = "2600:0c00:eaa:a$$$::/56"
  ipv6_cidr_block_network_border_group = "$region"
  # ipv6_netmask_length                  = "56"

```

But keep getting:

```
╷
│ Error: Missing required argument
│
│   with aws_vpc.$vpc_Name,
│   on main.tf line 7, in resource "aws_vpc" "$vpc_Name":
│    7:   ipv6_cidr_block                      = "2600:0c00:eaa:a$$$::/56"
│
│ "ipv6_cidr_block": all of `ipv6_cidr_block,ipv6_ipam_pool_id` must be specified

```

I've seen this:

**ipv6\_cidr\_block** \- can be set explicitly or derived from IPAM using ipv6\_netmask\_length.

**ipv6\_ipam\_pool\_id** \- conflicts with assign\_generated\_ipv6\_cidr\_block.

**ipv6\_netmask\_length** \- conflicts with ipv6\_cidr\_block. This can be omitted if IPAM pool as a allocation\_default\_netmask\_length set.

IPAM is not defined for the account:

```
aws ec2 describe-ipam-pools
- IpamPools: []

```

And this happens whether "ipv6\_netmask\_length" is set or not.

Please, what am I doing wrong and how do I set it right?

Thanks for the help.

# Answer
> 1 votes
As the error states:

> "ipv6\_cidr\_block": all of `ipv6_cidr_block,ipv6_ipam_pool_id` must be specified

Both `ipv6_cidr_block` and `ipv6_ipam_pool_id` must be *specified*. This doesn't necessarily mean they need to have a value, so in your case, you should be fine to just leave it empty:

```
ipv6_cidr_block   = "2600:0c00:eaa:a$$$::/56"
ipv6_ipam_pool_id = ""

```

---
Tags: terraform
---


# Question
Title: How do I release multiple projects to same domain using AWS when developer commit the latest code change
I have multiple projects on Github and I need to release each project on same domain different paths when developer commit code changes.

Example:

I have Github repositories like below

* CRM
* CMS
* Main-Website

currently, our website is like this

* example.com/CRM
* example.com/CMS
* example.com --\> is the Main-Website repository.

Please someone tell me how to do this in AWS using there services. Currently im doing this manually login to server and git pull

Thanks.

# Answer
> 0 votes
Finally, I found the answer a few years back! and here you go :D

In AWS, we have to use Cloudfront service to archive this.

Cloudfront has origin and behaviors settings, where you can define them.

For example:

If your domain name is: example.com

You can define the path: `example.com/crm` and you can map this path with `AWS Lambda function, EB or any related service`.

Likewise you will be able to create much as you want.

* `example.com/crm` to lambda
* `example.com/blog` to EB
* `example.com/app` to S3

Hope this helps someone.

# Answer
> 2 votes
You may wish to try scripting the actions you want. Then use git hooks to trigger your scripts to release the latest code to your environment. Alternatively, you could use something like Jenkins to configure a "push on green" system if you are working with compiled code. Lastly, (though I haven't used them) Amazon claims that their CodePipeline product can do this (and perhaps CodeBuild can as well), though my personal preference is to keep things as generic as possible and avoid drinking Amazon's Kool-Aid in order to keep things portable. Like a drug dealer, the first hit may be free with Amazon, and things are great until they have you hooked and decide to jack up the price. Utilizing my own open source system ensures that I can easily take my ball and go to another cloud or home altogether (and host it myself) in the event that I need to make a rapid exit from Amazon's cloud and avoids lock-in.

---
Tags: amazon-web-services, github
---


# Question
Title: How does Github Actions work with docker containers?
Consider this GA workflow:

```
name: My GA Workflow

on: push

jobs:
  myJobName:
    runs-on: ubuntu-latest
    container: cypress/included:10.6.0
    steps:
      - name: Ensure tools are available
        shell: bash
        run: |
          apt-get update && \
          apt-get install -y unzip zstd netcat

    # and so on...

```

I would like to have a crystal clear understanding what happens there. Currently I reckon:

1. GA will run a `ubuntu-latest` virtual machine with docker engine pre-installed.
2. It will pull and run `cypress/included:10.6.0`.
3. *All* the steps will run inside the Cypress docker container, not on the Ubuntu machine.

Is that correct?

# Answer
> 2 votes
Yes your understanding is correct. The full documentation is here https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container

# Answer
> 0 votes
1. We should have docker images in the dockerhub. if we require customized docker image we can create docker image using the docker file
2. We can create application.yml files by using github actions workflow.
3. Application.yaml file for docker containers looks like this:

name: container # Workflow-name

on: push #when a push is made to branch in the workflow's repository

jobs: # Actionsto be performed after push happened

node-docker:

```
runs-on: ubuntu-latest# Running OS on which actions will be performed

container:

  image: node:14.15.0-alpine3.12 # docker-image-tag, it will pull from Dockerhub and container get created

```

# Answer
> -1 votes
Creating a Dockerfile In your new hello-world-docker-action directory, create a new Dockerfile file. Make sure that your filename is capitalized correctly (use a capital D but not a capital f) if you're having issues. For more information, see "Dockerfile support for GitHub Actions."

Dockerfile

```
# Container image that runs your code
FROM alpine:3.10

# Copies your code file from your action repository to the filesystem path `/` of the container
COPY entrypoint.sh /entrypoint.sh

# Code file to execute when the docker container starts up (`entrypoint.sh`)
ENTRYPOINT ["/entrypoint.sh"]

```

Creating an action metadata file Create a new action.yml file in the hello-world-docker-action directory you created above. For more information, see "Metadata syntax for GitHub Actions."

action.yml

```
YAML
# action.yml
name: 'Hello World'
description: 'Greet someone and record the time'
inputs:
  who-to-greet:  # id of input
    description: 'Who to greet'
    required: true
    default: 'World'
outputs:
  time: # id of output
    description: 'The time we greeted you'
runs:
  using: 'docker'
  image: 'Dockerfile'
  args:
    - ${{ inputs.who-to-greet }}

```

This metadata defines one who-to-greet input and one time output parameter. To pass inputs to the Docker container, you should declare the input using inputs and pass the input in the args keyword. Everything you include in args is passed to the container, but for better discoverability for users of your action, we recommended using inputs.

GitHub will build an image from your Dockerfile, and run commands in a new container using this image.

---
Tags: docker, github-actions, workflow
---


# Question
Title: Can you delete project binaries from an Azure Devops repo
I have an existing repository in Azure DevOps that is currently tracking various /obj, /bin files (.dll, .pdb, .cache, etc.). I don't want to track these anymore; however I am worried that if I delete these files from my repository, then the project will break when I try to release it using a pipeline. Are these safe to exclude and delete, or do I need to manually include them somewhere? I don't have a good understanding of how these files are generated or what they're used for. Thanks.

# Answer
Do not store your generated binaries in git. Git stores every version of a binary as a full new version, not just the changes. Your projects must be setup in the way that the binaries can be rebuilt anywhere.

Then in the pipeline your code is copied to a second directory structure and the projects will build and generate the binaries for you. From there unit tests are done and whatever more is in the pipeline.

Use `git rm` to remove them from the repo (optional) `git filter-branch` to remove them from old commits `git gc --prune=now` to garbage collect them from the ..git directory
> 1 votes

---
Tags: git
---


# Question
Title: How to setup ExternalDNS on Microk8s cluster?
I have a Highly Available, 3 nods, Microk8s cluster with MetalLB and Ingress.

The cluster is supposed to serve a website with high availability.

I want to enable ExternalDNS for the website with the domain currently on Cloudflare (but I’m open to other free/commercial alternatives).

I have looked at the examples on the ExternalDNS repository but I can’t find any instructions for a similar setup.

Can anyone point me to a starting point, please?

# Answer
cloudflare DNS can be managed by external DNS setup, did you tried this, I have worked with this with DNS on digital ocean

https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/cloudflare.md
> 0 votes

# Answer
Run an application and expose it via a Kubernetes Service:

Example for nginx: example.org as a external DNS
> 0 votes

---
Tags: kubernetes, dns, servers
---


# Question
Title: Docker compose volume syntax valid for Windows and Linux
We have developers working on an app using both Windows and Linux. The application is built within a Docker container, and ships a docker-compose specification for the build environment.

The local directory is mounted as a volume:

```
    volumes:
      - ${PWD}:/tmp

```

however **this doesn't work in Windows** because `$PWD` is not defined.

My question is:

**Can we have a single `docker-compose.yml` to satisfy both the Windows and Linux developers?**

The obvious way to do this seems to me to have two docker-compose files, one for each OS.

# Answer
> 10 votes
Yes. Just use ./ for you current directory that the Docker-compose file is in. Your "working directory" for the compose file is just "./". If you are trying to set a directory below that it would look something like:

```
volumes:
* `./DirectoryIWantToTarget:/tmp`

```

There's an example of this in the Docker-Compose documentation here. This approach makes the solution cross-platform as well.

# Answer
> 3 votes
```
PS C:\Users\gaius> Write-Output $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      17763  592

PS C:\Users\gaius> Write-Output $pwd

Path
----
C:\Users\gaius

```

That appears to work as expected, what versions of things are you using?

Compare to Linux:

```
gaius@klossy:~$ pwsh
PowerShell 6.2.2
Copyright (c) Microsoft Corporation. All rights reserved.

https://aka.ms/pscore6-docs
Type 'help' to get help.

PS /home/gaius> echo $pwd

Path
----
/home/gaius

PS /home/gaius>

```

(`echo` is just an alias for `Write-Output`)

If you must have exact commonality between Windows and Linux there are a few solutions, Git comes with Bash for Windows, there's WSL, etc.

# Answer
> 2 votes
I think my case may be related as I also tried to configure environment for both Windows and Linux. I only have to mention that I am using `docker-compose` on WSL1 (Windows Subsystem for Linux) configured following by: this

I suggest you to try

My solution is (using the: long-syntax volumes definition from official docs):

```
version: '3.7'

services:
  web:
    build: ./DirectoryWithDockerfile
    volumes:
      - type: bind
        source: ./DirectoryIWantToMountInDockerContainer
        target: /path/where/mount/source
        volume:
          nocopy: true  # flag to disable copying of data from a container when a volume is created
    ports:
      - 8000:8000

```

I don't know why short syntax doesn't worked on Windows for me (and for you):

```
   volumes:  # this doesn't work and I don't know why
     - ./DirectoryIWantToMountInDockerContainer/:/path/where/mount/source

```

My Docker version: 19.03.5

docker-compose version: 1.25.4

# Answer
> 0 votes
```
volumes:
  - /usr/local/db-backup:/var/lib/mysql # On Linux, For backup data from the docker container to the host
  - D:/Docker_volumes/mysql/db-backup:/var/lib/mysql # On Windows, you need to config File Sharing with "D:" mounted when starting docker.

```

# Answer
> 0 votes
2022 update If you want to have a persistent database for docker(Windows) MySQL using docker Hyper-V

1. Make a folder at any location where you want to have your DB data for eg. D:\DockerDB
2. Now, use Docker in Hyper-v mode.
3. Go to settings -\> Resources -\> File sharing -\> add you DB data folder here.(D:\DockerDB) and apply and restart.

In your docker-compose.yml file add volumes as below

```
mysqldb:
    container_name: mysqldb
    image: mysql
    volumes:
      - D:/DockerDB:/var/lib/mysql

```

Now your data will persist on DB on your local machine.

---
Tags: docker-compose, linux, windows, environment-variables, volume
---


# Question
Title: What is limit of runs does Azure Devops pipeline keeps?
What is the limit, and where do you increase the default setting?

# Answer
> 0 votes
Project settings \> Settings

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


# Question
Title: How to properly escape brackets in ArgoCD?
I have an ArgoCD + Argo Workfows setup. In my manifests files, I am trying to escape double brackets since I have some helm apps, and if I manually edit the Argo workflow file with the expression below, it works. BUT if I push any changes my app gets degraded, with the following error: `cannot validate Workflow: templates.main.steps failed to resolve {{steps.scheduler.outputs.result}}` and this is what my config looks like:

```
    templates:
      - name: main
        steps:
        - - name: scheduler
            template: scheduler
          - name: step-1
            templateRef:
              name: step-1
              template: my-templates
            when: '"{{`{{steps.scheduler.outputs.result}}`}}" =~ example'

```

Any ideas? I think this might be Argocd related, since the error only appears there and I can manually run the workflow from Argo.

# Answer
> 1 votes
Try this "beauty":

```
{{ "'{{steps.scheduler.outputs.result}} =~ example'" }}

```
* {{ "" }} - instructs go template to consider anything within as a literal
* ' - is a faint attempt to keep it as a string value in YAML; it should be optional

---
Tags: kubernetes, helm, yaml
---


title: How to decrypt Jenkins password?

text:
# Question
Title: How to decrypt Jenkins password?
In my secrets folder I have these files

```
-rw-r--r--  1 root root  272 Oct  2 11:07 hudson.console.AnnotatedLargeText.consoleAnnotator
-rw-r--r--  1 root root   48 Sep 23 11:40 hudson.console.ConsoleNote.MAC
-rw-r--r--  1 root root   32 Sep 23 11:42 hudson.model.Job.serverCookie
-rw-r--r--  1 root root  272 Sep 23 11:39 hudson.util.Secret
-rw-r--r--  1 root root   32 Sep 23 11:16 jenkins.model.Jenkins.crumbSalt
-rw-r--r--  1 root root  256 Sep 23 11:16 master.key
-rw-r--r--  1 root root  272 Sep 23 11:16 org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY
-rw-r--r--  1 root root  272 Sep 23 11:49 org.jenkinsci.plugins.workflow.log.ConsoleAnnotators.consoleAnnotator
-rw-r--r--  1 root root   48 Sep 23 11:39 org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.mac

```

In my case hudson.utils.secrets is binary

```
od -h hudson.util.Secret
0000000 5f25 eee1 0763 1b49 c074 ee22 af85 4e10
0000020 00cf dd32 b568 fae3 257a 8d6e 1e56 d995

```

I installed groovy,I looked at HOW TO DECRYPT FROM CREDENTIALS What should I do?

# Answer
Jenkins uses string interpolation to take password as input and it uses AES to encrypt and protect secrets, credentials, and their respective encryption keys.

So, using direct or simple approach will not work. Although you can try to assign the password to a string variable and the print it in log it works in most the cases until the password itself is saved after encrypting.
> 0 votes

---
Tags: jenkins
---


# Question
Title: Share DNS name between two k8s services deployed in aws
I want to share the same dns name for two services exposing same port for different protocol. Earlier i was doing this with metallb with this annotation and metallb was sharing the same ip for two svc.

> metallb.universe.tf/allow-shared-ip: mykey

In the AWS environment metallb is not there and i want to use something similar. In internet i found this link https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/annotations/ for possible annotation in aws. but didn't find any dns shared annotation. Note :- My cluster is deployed using rke2 1.24.7 on aws instances. I am not using EKS.

# Answer
While I don't have extensive experience with it, I believe Istio and other service meshes are built for this (and more complex things).

https://www.alibabacloud.com/blog/597011

Looks like it has a "global" DNS name format for inter cluster routing in addition to the local format.

> Services in the same Kubernetes cluster have the same DNS suffix, for example, svc.cluster.local. Kubernetes DNS provides the DNS resolution capability for these services. To deploy a similar configuration for services in the remote cluster, we name the services in the remote cluster in the .global format.
>
> The Istio installation package includes a CoreDNS server that provides the DNS resolution capability for these services. To use the DNS resolution capability, you need to direct the DNS service of Kubernetes to the CoreDNS service. Then, the CoreDNS service will act as the DNS server for the .global DNS domain.
> 1 votes

---
Tags: kubernetes
---


# Question
Title: Docker containers are being restarted after logging in via SSH
Docker is installed on my Raspberry Pi with Raspberry OS and running it in rootless mode. I currently have 3 docker containers running on it. The containers are running with docker compose.

The problem is that after I login via SSH, all containers restart. This is also noticeable because the login is taking like 5-10 seconds until the prompt is visible.

What is also odd is that this does not happen consequently. I can reproduce it if there is like 10 seconds in between login attempts.

What I also notice is that when I exit the terminal with CTRL + D, all docker containers stop. They start again after logging in via SSH on the PI.

Docker version: Docker-ce: 5:20.10.21~3-0~debian-bullseye

All applications have a similar docker-compose file. One example is below:

```
version: '3'
services:
  pihole:
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp"
      - "9080:80/tcp"
      - "9443:443/tcp"
    environment:
      TZ: 'Europe/Amsterdam'
      # WEBPASSWORD: 'set a secure password here or it will be random'
    # Volumes store your data between container upgrades
    volumes:
       - './etc-pihole/:/etc/pihole/'
       - './etc-dnsmasq.d/:/etc/dnsmasq.d/'
    dns:
      - 127.0.0.1
      - 1.1.1.1
    # Recommended but not required (DHCP needs NET_ADMIN)
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
    cap_add:
      - NET_ADMIN
    restart: on-failure:3

```

After logging in:

```
pi@raspberrypi:~ $ docker ps
CONTAINER ID   IMAGE                          COMMAND                  CREATED          STATUS                            PORTS                                                                                NAMES
bd2350eaea48   linuxserver/unifi-controller   "/init"                  25 minutes ago   Up 3 seconds                      0.0.0.0:1900->1900/udp, :::1900->1900/udp, 0.0.0.0:5514->5514/tcp, :::5514->5514/tcp, 0.0.0.0:6789->6789/tcp, :::6789->6789/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:8443->8443/tcp, :::8443->8443/tcp, 0.0.0.0:8843->8843/tcp, :::8843->8843/tcp, 0.0.0.0:3478->3478/udp, :::3478->3478/udp, 0.0.0.0:10001->10001/udp, :::10001->10001/udp, 0.0.0.0:8880->8880/tcp, :::8880->8880/tcp   unifi-controller-unifi-controller-1
b6b1733befc6   pihole/pihole:latest           "/s6-init"               25 minutes ago   Up 3 seconds (health: starting)   0.0.0.0:53->53/udp, :::53->53/udp, 0.0.0.0:53->53/tcp, 0.0.0.0:67->67/udp, :::53->53/tcp, :::67->67/udp, 0.0.0.0:9080->80/tcp, :::9080->80/tcp, 0.0.0.0:9443->443/tcp, :::9443->443/tcp                                                                                pihole-pihole-1
47c751c5912b   nginx                          "/docker-entrypoint.…"   30 minutes ago   Up 3 seconds                      0.0.0.0:80->80/tcp, :::80->80/tcp                                                                                nginx-web-1
pi@raspberrypi:~ $ uptime
 20:15:56 up 1 day, 57 min,  1 user,  load average: 1.34, 1.13, 0.92
pi@raspberrypi:~ $

```

systemctl status docker

```
pi@raspberrypi:~ $ systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2022-11-18 19:18:10 GMT; 24h ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 667 (dockerd)
      Tasks: 10
        CPU: 39.118s
     CGroup: /system.slice/docker.service
             └─667 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Nov 18 19:18:07 raspberrypi dockerd[667]: time="2022-11-18T19:18:07.718884305Z" level=info msg="ClientConn switching balancer to \"pick_first\"" module=grpc
Nov 18 19:18:08 raspberrypi dockerd[667]: time="2022-11-18T19:18:08.414555267Z" level=info msg="[graphdriver] using prior storage driver: overlay2"
Nov 18 19:18:08 raspberrypi dockerd[667]: time="2022-11-18T19:18:08.443483656Z" level=warning msg="Unable to find memory controller"
Nov 18 19:18:08 raspberrypi dockerd[667]: time="2022-11-18T19:18:08.444127749Z" level=info msg="Loading containers: start."
Nov 18 19:18:09 raspberrypi dockerd[667]: time="2022-11-18T19:18:09.048346693Z" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a pre>
Nov 18 19:18:09 raspberrypi dockerd[667]: time="2022-11-18T19:18:09.263348211Z" level=info msg="Loading containers: done."
Nov 18 19:18:09 raspberrypi dockerd[667]: time="2022-11-18T19:18:09.951108267Z" level=info msg="Docker daemon" commit=3056208 graphdriver(s)=overlay2 version=20.10.21
Nov 18 19:18:09 raspberrypi dockerd[667]: time="2022-11-18T19:18:09.952013081Z" level=info msg="Daemon has completed initialization"
Nov 18 19:18:10 raspberrypi systemd[1]: Started Docker Application Container Engine.
Nov 18 19:18:10 raspberrypi dockerd[667]: time="2022-11-18T19:18:10.045252137Z" level=info msg="API listen on /run/docker.sock"

```

Why does this happen?

# Answer
> 0 votes
Apparently rootless mode runs Docker only when a user session starts. After stopping the session, Docker stops too.

I had to enable lingering: https://stackoverflow.com/questions/73299883/docker-containers-terminate-on-shell-logout

`$ loginctl enable-linger $UID`

---
Tags: docker
---


# Question
Title: port forward ssh from traefik reverse proxy on docker to a k3s container
I'm running a k3s cluster (1 master + 2 workers) and a docker traefik container on the same host (master). The traefik docker container is actually doing the reverse proxy stuff for tls which is working already on ports 80 and 443 for my different subdomains. I'm trying to get ssh working (for only one subdomain) too but without success so far.

* port 22 is open through ufw allow (on Ubuntu 22.04)
* traefik rules are set as following:

```
    tcp:
      routers:
        giti-ssh:
          entrypoints:
            - "https" # tried also with a ssh entryoint
          rule: "HostSNI(`*`)"
          tls: {}
          service: giti-ssh
      services:
        giti-ssh:
          loadBalancer:
            servers:
              - address: "10.42.0.232:22"

```
* k3s is running flannel and metallb where the externalIP-range is at 10.42.0.230-250
* ip a shows (the interesting parts):

```
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:19:ea:c3 brd ff:ff:ff:ff:ff:ff
    altname enp11s0
    inet "private"/32 metric 100 scope global dynamic ens192
       valid_lft 36147sec preferred_lft 36147sec
    inet 10.42.0.200/32 scope global ens192
       valid_lft forever preferred_lft forever
    inet6 "private"/64 scope link
       valid_lft forever preferred_lft forever
3: br-5014eb2ffdf2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:7e:ab:72:98 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-5014eb2ffdf2
       valid_lft forever preferred_lft forever
    inet6 fe80::42:7eff:feab:7298/64 scope link
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:a5:03:77:2c brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
7: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
    link/ether 42:1b:d3:49:d3:6b brd ff:ff:ff:ff:ff:ff
    inet 10.42.0.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::401b:d3ff:fe49:d36b/64 scope link
       valid_lft forever preferred_lft forever
8: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
    link/ether e2:27:27:96:96:7e brd ff:ff:ff:ff:ff:ff
    inet 10.42.0.1/24 brd 10.42.0.255 scope global cni0
       valid_lft forever preferred_lft forever
    inet6 fe80::e027:27ff:fe96:967e/64 scope link
       valid_lft forever preferred_lft forever

```
* the containers are set up and the service for the one for ssh is listening on port 22 as type: LoadBalancer
* I can connect to that container through another service and IP on port 443 from the traefik reverse proxy but am missing something for port 22 and I think it has something to do with the traefik HostSNI or maybe the iptables....
* versions: docker traefic: latest (just for testing, am going for a tagged version..) k3s: v1.24.6+k3s1

I can't connect also through 1932/udp (minecraft), so I suppose running traefik on s.th. else then http(s) is harder....

Can s.o. give me a hint on how to achieve this.

Thanks in advance! jim

# Answer
> 0 votes
Your ip show does mention 10.42.0.0/32, 10.42.0.200/32. No traces of 10.42.0.232, though.

From LAN/outside SDN: can you connect any TCP port, or ping that address? anything that answers? I suspect nothing would.

In addition to that Traefik rule, you mentioned creating a Service ... Are you sure you did it right? Look at `kubectl get svc -A | grep 10.42.0.200`, that would give you a working example -- something with an externalIP/externalIPs set, or some status.loadbalancer.ingress array ... configuration may vary, depending on how external IPs were implemented and kube version, ..

And by the way, creating such Services: are you pointing to your application directly, or is it sent to Traefik instead? Assuming the latter: are you sure Traefik actually listens on such port.

Also, while Traefik should be able to process TCP or UDP trafic, unless you can easily have several Services & backends accessible through the same proto/port combination: involving your ingress controller here might not be necessary.

---
Tags: docker, kubernetes, k3s, traefik
---


# Question
Title: How to update Docker Swarm services all at once?
I have a Docker Swarm with three services: `proxy`, `backend`, `frontend`.

Currently it seems that if I do `docker stack deploy` and one service fails, it might just rollback to the previous version while the rest will be on the new version.

I want to ensure two things:

1. A request coming to `proxy` will always be served **by the same combination of service versions.** Doesn't matter if old or new, but I don't want `proxy:v2` to route a request to `backend:v1`.
2. **No downtime during an upgrade.** `proxy:v1` should continue serving requests until the full set of new services is ready, and only then the failover should happen.

Is this possible?

# Answer
> 1 votes
To ensure a stack is in a consistent state after an upgrade, see the documentation on update\_config. `failure_action` defaults to `pause` so you need to set it to `continue` to ensure docker updates the services regardless.

```
services:
  proxy:
    deploy:
      update_config:
        on_failure: continue
  backend:
    deploy:
      update_config:
        on_failure: continue

```

That said - docker does not support green/blue deployments - but it is possible to use network aliases to ensure proxy:2 does not route to backend:1. Something like this for e.g.:

```
services:
  proxy:
    image: proxy:${VER}
    environment:
      BACKEND_HOST: backend-${VER}

  backend:
    image: backend:${VER}
    networks:
      default:
        aliases: ["backend-${VER}"]

```

To achieve your final requirement, you need to set the `update_config` `parallelism` to 1, and ensure that the `order` is set to `start-first`.

A naive deployment would have a race condition if "proxy:2" is available before "backend:2" is available, but as long as there is a healthcheck, "proxy:2" can prevent itself receiving traffic until it has a successful connection test to "backend-2"

```
services:
  proxy:
    image: proxy:${VER}
    environment:
      BACKEND_HOST: backend-${VER}
    healthcheck: ["CMD", "/bin/sh","-c","test_backend.sh"]

```

Of course, you can run into problems if "proxy:2" finishes deploying, but "backend:2" errors out - you could eventually have a situation where you have no proxy:1 running, only proxy:2, but only backend:1 running and no backend:2. So you want to ensure the `update_config` delays updating the next task until the current one is health - or pause if that never happens.

PS. It seems potentially much less hassle to just design and code around the principal that backwards compatibility of +-1 version is expected.

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


# Question
Title: Is there a way to get message in Teams and Azure DevOps when someone mentions me in a comment in a Work Item or Pull Request?
Usually Azure DevOps send the notifications as **Email**:  but I want

* Get a message in a chat in Teams
* Get a notification inside the Azure DevOps environment (for example in top bar)

**when someone mentions me** in a comment in a *Work Item* or *Pull Request*.

Is there an extension or special way to having these features?

# Answer
> 0 votes
Yes, you can do this. Azure DevOps you can use webhooks directly to teams, just lookaround for implementation.

GitHub, you can use WebHook and send the message to an ETL, like LogicApp that will send the message to teams, or you can make your own middleware, there are some options to comunicate with teams (https://docs.microsoft.com/en-us/microsoftteams/platform/sbs-gs-csharp)

# Answer
> 0 votes
Did you find an answer to this?

I looked into using Power Automate within teams but the only options are:

It appears all the options with dev ops itself are just for email... not very useful unless you're checking email all day every day (which is not conducive to getting a lot done!)

---
Tags: azure-devops
---


# Question
Title: Clarity on Azure DevOps parallel job "consumption"
We're in the process of moving away from Visual Studio's web publish into Azure DevOps and require some clarity on how parallel jobs are "consumed", or an alternative way to quickly deploy our application to multiple destinations.

Our web application has a single code-base and is published into 15 separate clients' hosting areas (all on Azure App Services), each with their own configuration file transform during the final deployment process, e.g.:

Currently the process is working well on Azure DevOps' "free" account, but it takes around one hour to deploy to each client hosting environment as the processes run in a queue (`Deploy Customer 1``Deploy Customer 2` → ...).

Yesterday to streamline the process and get the deployments done asynchronously we purchased three "Parallel Jobs" from the billing area. Deployment was indeed much quicker as three ran in parallel. However, when they were finished there were no parallel jobs available in our account.

The terminology in the Learn portal talks about monthly resources, so we had assumed that the parallel job agents were a one-month purchase (buy once/use many in that month).

If they are consumed immediately upon completion then according to the pricing calculator, if have a weekly release and use 15 parallel jobs then that will cost me over £2,000 per month (£35.34 * 15 * 4) which seems unbelievably expensive for a short time saver.

Can anyone please clarify the situation, or suggest an alternative method for deploying asynchronously?

# Answer
I can't comment, so using an answer.

What exactly do you mean by "However, when they were finished there were no parallel jobs available in our account." If you use the MS hosted agents, and if you bought three parallel jobs, you should see them in the Organization settings -\> Parallel jobs overview. If not, try lo log out, clear cache etc. The purchases are indeed for a month, as explained here, the costs would be about 40 euros for a month, so for three it would be around 120 euro a month.

As an alternative, and as suggested by others, you could use self hosted agents. They are cheaper, and depending on resources on the host where you install the agent, they run faster.

And then, depending on your needs, there are several ways that might speed up your deployment process, but that usually depends on what you've already configured and your needs.

And then last, if you are a really early user of DevOps, there was an option to pay for hosted agents by the minute. That could explain your situation, but I've checked several organizations inclusing a few already several years old but I can't find any reference of it.
> 2 votes

# Answer
If your pipeline exceeds the maximum job timeout, try splitting your pipeline into multiple jobs. Here is the docs for it https://learn.microsoft.com/en-us/azure/devops/pipelines/process/phases?view=azure-devops
> 0 votes

# Answer
So we use privately hosted agents and it saves us a lot of money, here are some details

**Public project** Up to 10 free Microsoft-hosted parallel jobs that can run for up to 360 minutes (6 hours) each time No overall time limit per month

**Private project** One free job that can run for up to 60 minutes each time 1,800 minutes (30 hours) per mont. You can pay extra to get parallel jobs.

**Self Hosted Agent** You can just setup your own self hosted agents, it just a script you run on a VM, takes about 10min per agent plus of course you need to install the software you need on the agent(s) and then you don't have those restrictions.
> 0 votes

---
Tags: azure-devops, release-management
---


# Question
Title: kubernetes - trouble adding node to cluster
by following the information in this video, I was able to get a control plane running on my kmaster vm.

```
jason@kmaster:~$ kubectl get pods -A
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-59697b644f-tpxnn   1/1     Running   0          18h
kube-system   calico-node-88l8f                          1/1     Running   0          18h
kube-system   coredns-565d847f94-vpzwg                   1/1     Running   0          18h
kube-system   coredns-565d847f94-wkv4p                   1/1     Running   0          18h
kube-system   etcd-kmaster                               1/1     Running   0          18h
kube-system   kube-apiserver-kmaster                     1/1     Running   0          18h
kube-system   kube-controller-manager-kmaster            1/1     Running   0          18h
kube-system   kube-proxy-wd2gh                           1/1     Running   0          18h
kube-system   kube-scheduler-kmaster                     1/1     Running   0          18h

```

Here are my network interfaces:

```
jason@kmaster:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether e6:ec:4b:b8:37:7a brd ff:ff:ff:ff:ff:ff
    altname enp0s18
    inet 10.0.10.118/24 brd 10.0.10.255 scope global ens18
       valid_lft forever preferred_lft forever
    inet6 2600:8802:5700:46d::164d/128 scope global dynamic noprefixroute
       valid_lft 4863sec preferred_lft 2163sec
    inet6 2600:8802:5700:46d:e4ec:4bff:feb8:377a/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 86385sec preferred_lft 14385sec
    inet6 fe80::e4ec:4bff:feb8:377a/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:bb:62:1c:c5 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
4: calida7207728a2@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::ecee:eeff:feee:eeee/64 scope link
       valid_lft forever preferred_lft forever
5: cali919c5dc3a63@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::ecee:eeff:feee:eeee/64 scope link
       valid_lft forever preferred_lft forever
6: cali0657a847784@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::ecee:eeff:feee:eeee/64 scope link
       valid_lft forever preferred_lft forever
7: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
    inet 192.168.189.0/32 scope global tunl0
       valid_lft forever preferred_lft forever

```

I am now trying to add a node to the cluster by using the following command:

```
sudo kubeadm join 10.0.10.118:6443 --token <token>         --discovery-token-ca-cert-hash sha256:<hash>
Found multiple CRI endpoints on the host. Please define which one do you wish to use by setting the 'criSocket' field in the kubeadm configuration file: unix:///var/run/containerd/containerd.sock, unix:///var/run/cri-dockerd.sock
To see the stack trace of this error execute with --v=5 or higher

```

As you can see it says 'please define which one you wish to use by setting the 'criSocket' field in the kubeadm configuration file. However when I try to edit /var/run/cri-dockerd.sock file, it says it's not a normal file:

```
cri-dockerd.sock is not a regular file (use -f to see it)

```

Here is my kubeadm config print:

```
jason@kmaster:~$ kubectl get pods -A --watch
NAMESPACE     NAME                                       READY   STATUS    RESTARTS        AGE
kube-system   calico-kube-controllers-59697b644f-tpxnn   1/1     Running   2 (6m56s ago)   16d
kube-system   calico-node-88l8f                          1/1     Running   2 (6m56s ago)   16d
kube-system   coredns-565d847f94-vpzwg                   1/1     Running   2 (6m51s ago)   16d
kube-system   coredns-565d847f94-wkv4p                   1/1     Running   2 (6m51s ago)   16d
kube-system   etcd-kmaster                               1/1     Running   2 (6m56s ago)   16d
kube-system   kube-apiserver-kmaster                     1/1     Running   2 (6m55s ago)   16d
kube-system   kube-controller-manager-kmaster            1/1     Running   2 (6m56s ago)   16d
kube-system   kube-proxy-wd2gh                           1/1     Running   2 (6m56s ago)   16d
kube-system   kube-scheduler-kmaster                     1/1     Running   2 (6m56s ago)   16d
^Cjason@kmaster:~kubeadm config print init-defaults
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 1.2.3.4
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  imagePullPolicy: IfNotPresent
  name: node
  taints: null
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
kind: ClusterConfiguration
kubernetesVersion: 1.25.0
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
scheduler: {}

```

Under nodeRegistration it says: nodeRegistration: criSocket: unix:///var/run/containerd/containerd.sock

In /var/run/ I see cri-dockerd.sock

```
jason@kmaster:/var/run$ ls -la
total 28
srw-rw----  1 root docker    0 Nov 15 00:25 cri-dockerd.sock

```

How can I add my node to the cluster?

# Answer
You can choose which CRI you would like to use directly from the join command by adding this flag: (see `kubeadm join --help` for details)

```
--cri-socket string

```

here, string will be one of the two available sockets displayed in the error:

1. `unix:///var/run/containerd/containerd.sock`
2. `unix:///var/run/cri-dockerd.sock`

Or you can also add it to you kubeadm config as stated see doc here: https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/#kubeadm-k8s-io-v1beta3-NodeRegistrationOptions
> 1 votes

# Answer
I got around this by starting over, installing ubuntu 20.04 and then creating cluster again. But it believe maxxvw is correct.
> 0 votes

---
Tags: kubernetes
---


# Question
Title: Is there a Way to Run a Docker Image without installing it in server?
I have created a Laravel application that I tried to deploy in a shared host (other apps running). It creates a conflict with the other project at the point to observe CSRF interferences at the other applications. So I decided to containerize my application. But when I log into the server there is no tool to manage those containers.

How can I deploy a containerizer docker app into my server? Does there exist some tool that I can put inside a folder with the docker image and runs exposing the port to work?

My server has cpanel but not WHM.

# Answer
> 1 votes
It is possible to run containers as a regular user using podman (buzzword: rootless).

Note that while podman is based on the same OCI standard as docker, there are some differences in the details. For example, healthchecks are specific to docker.

# Answer
> 0 votes
I don't believe you can put it in a folder because the docker management tools require that docker be installed on the server. You should check to see if your server has Docker installed. Because you mentioned having only cPanel access and no WHM, I assume you don't have root access to the server (shared server hosting does not allow root access). Also, I believe cPanel does not include docker by default, and even if it does, installation requires root access.

You may check some StackOverflow responses and guides for "Publishing Laravel on a cPanel Shared Hosting" here: How-to-deploy-docker-containers-to-shared-hosting

# Answer
> 0 votes
Well, without access to CLI and root (to install the engine) it is virtually next to impossible. It doesn't matter if you want docker, podman, or even runc (OCI), you simply don't have it.

The suggestion can be to run a server with the full root access, from Digital Ocean, OVH (there is many providers), so you can work with containers.

---
Tags: docker, php, sysadmin
---


# Question
Title: Why is my AWS Application Load Balancer not exposing my Kubernetes service?
I am following a tutorial to set Kubernetes with an ingress managed service. The cluster is,

* 1 controller
* 2 worker Kubernetes cluster
* kubeadm built
* running Kubernetes v1.25.3 (latest at the time of writing)
* running weave-net
* running ingress-nginx
* EC2, *not* EKS

I am just expecting to see the nginx default page when I access the AWS Application Load Balancer, ALB, DNS name - nothing fancy.

I first used this helm chart to deploy nginx-ingress, as per the "Quick start" docs.

```
helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

```

I then deployed the following in the `default` namespace.

ingress.yaml

```
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: default
spec:
  ingressClassName: nginx
  rules:
  - host: ***alb***.elb.amazonaws.com
    http:
      paths:
      - backend:
          service:
            name: nginx-service
            port:
              number: 8080
        path: /
        pathType: Exact

```

service.yaml

```
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
    svc: test-nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80

```

deployment.yaml

```
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
    svc: test-nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80

```

```
k get svc -A

```

```
NAMESPACE       NAME                                 TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
default         demo                                 ClusterIP      *****            <none>        80/TCP                       7h53m
default         kubernetes                           ClusterIP      *****            <none>        443/TCP                      2d6h
default         nginx-service                        ClusterIP      *****            <none>        8080/TCP                     26h
ingress-nginx   ingress-nginx-controller             LoadBalancer   *****            <pending>     80:32573/TCP,443:32512/TCP   35h
ingress-nginx   ingress-nginx-controller-admission   ClusterIP      *****            <none>        443/TCP                      35h
kube-system     kube-dns                             ClusterIP      *****            <none>        53/UDP,53/TCP,9153/TCP       2d6h

```

Two AWS security groups are in effect, one for the controller and one for the workers. Both these security groups have ports 6783 - 6784 open as required by ingress-nginx.

The ALB is set with the following.

* same Availability Zones as the worker nodes
* default (open) security group
* Listener protocol:port = HTTP:80
* same VPC as the EC2 instances.
* Scheme = internet-facing
* IP address type = ipv4

The target group for this ALB is set as follows.

* both worker nodes
* Protocol : Port = HTTP: 32573
* Protocol version = HTTP1
* same VPC as the EC2 instances.
* Health path = /

On the assumption that the target group would block traffic to "unhealthy" nodes, I previously deployed a separate service directly on a different `NodePort`, rather than via `Ingress`, to fudge the health check to *Healthy*, but this made no difference.

I have,

* double checked that I have followed the steps in the tutorial *exactly*
* looked through the logs but cannot find anything that would suggest an error.
* terminated all the pods.
* restarted the nodes.

When I run

```
k logs ingress-nginx-controller-***** -n ingress-nginx

```

It returns

```
-------------------------------------------------------------------------------
NGINX Ingress controller
  Release:       v1.4.0
  Build:         50be2bf95fd1ef480420e2aa1d6c5c7c138c95ea
  Repository:    https://github.com/kubernetes/ingress-nginx
  nginx version: nginx/1.19.10

-------------------------------------------------------------------------------

W1021 13:49:00.607448       7 client_config.go:617] Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.
I1021 13:49:00.607678       7 main.go:209] "Creating API client" host="https://10.96.0.1:443"
I1021 13:49:00.613511       7 main.go:253] "Running in Kubernetes cluster" major="1" minor="25" git="v1.25.3" state="clean" commit="434bfd82814af038ad94d62ebe59b133fcb50506" platform="linux/amd64"
I1021 13:49:00.776507       7 main.go:104] "SSL fake certificate created" file="/etc/ingress-controller/ssl/default-fake-certificate.pem"
I1021 13:49:00.788407       7 ssl.go:533] "loading tls certificate" path="/usr/local/certificates/cert" key="/usr/local/certificates/key"
I1021 13:49:00.807812       7 nginx.go:260] "Starting NGINX Ingress controller"
I1021 13:49:00.820423       7 event.go:285] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"ingress-nginx", Name:"ingress-nginx-controller", UID:"f4d537f7-2b89-4fe5-a9ed-c064533b08a2", APIVersion:"v1", ResourceVersion:"96138", FieldPath:""}): type: 'Normal' reason: 'CREATE' ConfigMap ingress-nginx/ingress-nginx-controller
I1021 13:49:01.910567       7 store.go:430] "Found valid IngressClass" ingress="default/my-app-ingress" ingressclass="nginx"
I1021 13:49:01.910942       7 event.go:285] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"my-app-ingress", UID:"9111168a-9dc8-4cf8-a0f6-fe871c3ada61", APIVersion:"networking.k8s.io/v1", ResourceVersion:"245885", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync
I1021 13:49:02.009443       7 nginx.go:303] "Starting NGINX process"
I1021 13:49:02.009750       7 leaderelection.go:248] attempting to acquire leader lease ingress-nginx/ingress-controller-leader...
I1021 13:49:02.010156       7 nginx.go:323] "Starting validation webhook" address=":8443" certPath="/usr/local/certificates/cert" keyPath="/usr/local/certificates/key"
I1021 13:49:02.010553       7 controller.go:168] "Configuration changes detected, backend reload required"
I1021 13:49:02.015673       7 status.go:84] "New leader elected" identity="ingress-nginx-controller-567c84f6f-8s5zv"
I1021 13:49:02.081076       7 controller.go:185] "Backend successfully reloaded"
I1021 13:49:02.081398       7 controller.go:196] "Initial sync, sleeping for 1 second"
I1021 13:49:02.081913       7 event.go:285] Event(v1.ObjectReference{Kind:"Pod", Namespace:"ingress-nginx", Name:"ingress-nginx-controller-567c84f6f-52k47", UID:"fa2b26ad-0594-4e43-927a-11a9def12467", APIVersion:"v1", ResourceVersion:"249556", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration
I1021 13:49:43.652768       7 leaderelection.go:258] successfully acquired lease ingress-nginx/ingress-controller-leader
I1021 13:49:43.652910       7 status.go:84] "New leader elected" identity="ingress-nginx-controller-567c84f6f-52k47"
W1021 14:22:31.247404       7 controller.go:1112] Service "default/demo" does not have any active Endpoint.
I1021 14:22:31.283535       7 admission.go:149] processed ingress via admission controller {testedIngressLength:2 testedIngressTime:0.036s renderingIngressLength:2 renderingIngressTime:0s admissionTime:25.8kBs testedConfigurationSize:0.036}
I1021 14:22:31.283727       7 main.go:100] "successfully validated configuration, accepting" ingress="default/demo"
I1021 14:22:31.289380       7 store.go:430] "Found valid IngressClass" ingress="default/demo" ingressclass="nginx"
I1021 14:22:31.289790       7 event.go:285] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"demo", UID:"50962ac3-d7f1-45bc-8e73-7baf6337331b", APIVersion:"networking.k8s.io/v1", ResourceVersion:"252977", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync
W1021 14:22:31.290058       7 controller.go:1112] Service "default/demo" does not have any active Endpoint.
I1021 14:22:31.290210       7 controller.go:168] "Configuration changes detected, backend reload required"
I1021 14:22:31.366582       7 controller.go:185] "Backend successfully reloaded"
I1021 14:22:31.367273       7 event.go:285] Event(v1.ObjectReference{Kind:"Pod", Namespace:"ingress-nginx", Name:"ingress-nginx-controller-567c84f6f-52k47", UID:"fa2b26ad-0594-4e43-927a-11a9def12467", APIVersion:"v1", ResourceVersion:"249556", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration
I1021 14:25:34.757766       7 controller.go:168] "Configuration changes detected, backend reload required"
I1021 14:25:34.827908       7 controller.go:185] "Backend successfully reloaded"
I1021 14:25:34.828291       7 event.go:285] Event(v1.ObjectReference{Kind:"Pod", Namespace:"ingress-nginx", Name:"ingress-nginx-controller-567c84f6f-52k47", UID:"fa2b26ad-0594-4e43-927a-11a9def12467", APIVersion:"v1", ResourceVersion:"249556", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration
I1021 14:25:41.191636       7 admission.go:149] processed ingress via admission controller {testedIngressLength:1 testedIngressTime:0.036s renderingIngressLength:1 renderingIngressTime:0s admissionTime:22.1kBs testedConfigurationSize:0.036}
I1021 14:25:41.191800       7 main.go:100] "successfully validated configuration, accepting" ingress="default/my-app-ingress"
I1021 14:25:41.195876       7 event.go:285] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"my-app-ingress", UID:"9111168a-9dc8-4cf8-a0f6-fe871c3ada61", APIVersion:"networking.k8s.io/v1", ResourceVersion:"253276", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync
I1021 20:40:45.084934       7 admission.go:149] processed ingress via admission controller {testedIngressLength:1 testedIngressTime:0.049s renderingIngressLength:1 renderingIngressTime:0s admissionTime:22.1kBs testedConfigurationSize:0.049}
I1021 20:40:45.085124       7 main.go:100] "successfully validated configuration, accepting" ingress="default/my-app-ingress"
I1021 20:40:45.088698       7 controller.go:168] "Configuration changes detected, backend reload required"
I1021 20:40:45.088779       7 event.go:285] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"my-app-ingress", UID:"9111168a-9dc8-4cf8-a0f6-fe871c3ada61", APIVersion:"networking.k8s.io/v1", ResourceVersion:"287850", FieldPath:""}): type: 'Normal' reason: 'Sync' Scheduled for sync
I1021 20:40:45.183140       7 controller.go:185] "Backend successfully reloaded"
I1021 20:40:45.184054       7 event.go:285] Event(v1.ObjectReference{Kind:"Pod", Namespace:"ingress-nginx", Name:"ingress-nginx-controller-567c84f6f-52k47", UID:"fa2b26ad-0594-4e43-927a-11a9def12467", APIVersion:"v1", ResourceVersion:"249556", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration

```

I notice that the following appears in the logs for the weave-net pods.

```
k logs weave-net-*w1* -n kube-system

```

Where `*w1*` is the pod running on worker node1.

```
INFO: 2022/10/21 13:49:27.195158 ->[*controller*:6783] error during connection attempt: dial tcp :0->*controller*:6783: connect: connection refused

```

Where `*controller*` is the IP address of the control node.

After all of the above, when I navigate to the ALB DNS address, I just get,

`internal error - server connection terminated`

This is clearly a PEBKAC, but what am I missing?

# Answer
> 0 votes
The load balancer will connect to the default security group by default. This security group has a source of itself, which basically means that it blocks everything.

Add the inbound rule of all traffic from "Anywhere-IPv4" to ensure that all traffic can access the load balancer.

# Answer
> 0 votes
Check Security Groups again. Ensure, that SG used for Kubernetes service is open for your ALB SG (the best practice clearly said, you shouldn't use defasults, please, create a new one).

ALB must have Target Group. Check events for this TG, you will see the messages, you should see errors if any.

---
Tags: kubernetes, amazon-web-services, amazon-ec2, ingress-nginx
---


# Question
Title: Unable to login as `ubuntu` user on ec2 instance spawned from auto scaling group
Utilizing Ansible AWS modules, I'm creating an AMI from an existing EC2 instance where I am able to ssh with both my user and default account (ubuntu). After the AMI is in a ready state, I then create a launch template with the new AMI and an autoscaling group that leverages that launch template. Once the instance from the autoscaling group is stood up, I am only able to ssh with the user account, but not the default name. The `key_name` used for the first instance and the launch template are identical. The `/etc/ssh/sshd_config` file is also identical between the first instance and the autoscaled instance. The two instances also use the same security groups with port 22 accepting ssh traffic. I assume there might be some data lost during the AMI creation event, but I'm not sure. Any and all help would be appreciated and I'd be happy to provide more information if needed. Thank you!

```
- name: Create a sandbox instance
  hosts: localhost
  become: False
  gather_facts: False
  tasks:
    - name: Launch instance
      ec2_instance:
        key_name: "{{ keypair }}"
        security_group: "{{ security_group }}"
        instance_type: "{{ instance_type }}"
        image_id: "{{ image }}"
        wait: true
        region: "{{ region }}"
        vpc_subnet_id: "{{ vpc_subnet_id }}"
        volumes:
          - device_name: /dev/sda1
            ebs:
              volume_size: 50
              delete_on_termination: true
        network:
          assign_public_ip: true
        tags:
          tmp: instance
      register: ec2

    - name: Debug EC2 variable availability
      ansible.builtin.debug:
        msg: ec2 instance {{ ec2.instances[0].network_interfaces[0].private_ip_address }}

    - name: Add new instance to host group
      add_host:
        hostname: "{{ ec2.instances[0].network_interfaces[0].private_ip_address }}"
        groupname: launched

    - name: Wait for SSH to come up
      delegate_to: "{{ ec2.instances[0].network_interfaces[0].private_ip_address }}"
      remote_user: "{{ bootstrap_user }}"
      wait_for_connection:
        delay: 60
        timeout: 320

- name: Configure instance
  hosts: launched
  become: True
  gather_facts: True
  remote_user: "{{ bootstrap_user }}"
  roles:
    - app_server
    - ruby
    - nginx
    - Datadog.datadog
  vars:
    datadog_checks:
      sidekiq:
        logs:
          - type: file
            path: /var/log/sidekiq.log
            source: sidekiq
            service: sidekiq
            tags:
              - "env:{{rails_env}}"

- hosts: launched
  become: yes
  gather_facts: no
  remote_user: "{{ user_name }}"
  become_user: "{{ user_name }}"
  # Need to set this hostname appropriately
  pre_tasks:
    - name: set hostname
      set_fact: hostname="sidekiq"
  roles:
    - deploy_app

- hosts: launched
  become: yes
  gather_facts: no
  remote_user: "{{ bootstrap_user }}"
  roles:
    - sidekiq

- name: Generate AMI from newly generated EC2 instance
  hosts: localhost
  gather_facts: False
  pre_tasks:
    - set_fact: ami_date="{{lookup('pipe','date +%Y%m%d%H%M%S')}}"
  tasks:
    - name: Debug EC2 instance variable availability
      ansible.builtin.debug:
        msg: EC2 Instances {{ ec2.instances }}

    - name: Create AMI
      ec2_ami:
        instance_id: "{{ ec2.instances[0].instance_id }}"
        name: "sidekiq_ami_{{ ami_date }}"
        device_mapping:
          - device_name: /dev/sda1
            size: 200
            delete_on_termination: true
            volume_type: gp3
        wait: True
        tags:
          env: "{{ rails_env }}"
      register: ami

    # - name: Terminate instances that were previously launched
    #   ec2:
    #     state: "absent"
    #     instance_ids: "{{ ec2.instances[0].instance_id }}"
    #     region:

    - name: Debug AMI variable availability
      ansible.builtin.debug:
        msg: AMI {{ ami }}

    - name: Create an ec2 launch template from new Sidekiq AMI
      ec2_launch_template:
        template_name: "sidekiq_launch_template_{{ rails_env }}"
        image_id: "{{ ami.image_id }}"
        key_name: "{{ keypair }}"
        instance_type: "{{ instance_type }}"
        disable_api_termination: true
        block_device_mappings:
          - device_name: /dev/sda1
            ebs:
              volume_size: 200
              volume_type: gp3
              delete_on_termination: true
        network_interfaces:
          - device_index: 0
            associate_public_ip_address: yes
            subnet_id: "{{ subnet_id }}"
            groups: ["{{ security_group }}"]
        user_data: "{{ '#!/bin/bash\nsudo systemctl sidekiq.service restart' | b64encode }}"
      register: template

    # Rolling ASG update with new launch template
    - name: Rolling update of the existing EC2 instances
      ec2_asg:
        name: "sidekiq_autoscaling_group_{{ rails_env }}"
        availability_zones:
          - us-west-1a
        launch_template:
          launch_template_name: "sidekiq_launch_template_{{ rails_env }}"
        health_check_period: 60
        health_check_type: EC2
        replace_all_instances: yes
        min_size: "{{ min_size }}"
        max_size: "{{ max_size }}"
        desired_capacity: "{{ desired_capacity }}"
        region: "{{ region }}"
        tags:
          - env: "{{ rails_env }}"
            Name: "{{ rails_env }}-sidekiq"
        vpc_zone_identifier: ["{{ subnet_id }}"]
      register: asg

```

# Answer
> 1 votes
Apparently during the AMI creation process, the default user password gets locked - a ! is appended to the password in `/etc/shadow`.

I was able to just add `passwd -u ubuntu` to the user data of the launch template to unlock it and we are good to go.

---
Tags: amazon-web-services, ansible, ansible-galaxy
---


# Question
Title: Port forwarding rules with Traefik and Docker.Compose
I'm trying to use Traefik to route to a number of services all running using docker-compose. What I'd like to do is access each service with a prefix, eg: 10.20.30.40/u10/xyz and 10.20.30.40/a10/abc instead of 10.20.30.40:8000/xyz and 10.20.30.40:8001/abc.

I have a \`docker-compose.yml file where I'm starting my services a10,u10,x10, mongo,mosquitto and all are exposed on their own ports - this works. I'm now stuck with the correct parameters for Traefik. You can see some of the attempts and commenting out of parameters.

The services a10,u10 etc should only be accessible using a prefix and all over port 80. Load balancing should be possible, eg: `docker-compose -f dc.yml --scale u10=3 --scale a10=5`

When I run this if I try on my local machine: http://127.0.0.1/u10/somepage.html I get a gateway timeout error, or, if I don't try using --scale then I'll get a 404.

Internally these services communicate with each other over the specified ports (REST) without the prefix and this works internally.

```
version: "3"
services:
   reverse-proxy:
     image: traefik:v2.9
     command:
       - "--log.level=DEBUG"
       - "--api.insecure=true"
       - "--providers.docker=true"
       - "--providers.docker.exposedByDefault=true"
       - "--entrypoints.web.address=:80"
       - "--accesslog=true"
     ports:
       - "80:80"
       - "8080:8080"
     volumes:
       - /var/run/docker.sock:/var/run/docker.sock

   u10:
     image: "u10"
#     container_name: u10
#     ports:
#       - 8540:8540                           # !!!
     depends_on:
       - messagebus
     restart: always
     networks:
      - attestationnetwork
     volumes:
      - ./a10.conf:/etc/a10.conf      # !!!
     labels:
       - "traefik.enable=true"
 #      - "traefik.port=8540"
       - "traefik.docker.network=my-internal-network"
       - "traefik.http.routers.u10.rule=PathPrefix(`/u10`)"
       - "traefik.http.routers.u10.entrypoints=web"
       - "traefik.http.routers.u10.middlewares=u10"
       - "traefik.http.middlewares.u10.stripprefix.prefixes=/u10"
       - "traefik.http.middlewares.u10.stripprefix.forceSlash=false"
       - "traefik.http.routers.u10.service=u10"
       - "traefik.http.services.u10.loadbalancer.server.port=8540"

networks:
   my-internal-network:
     driver: bridge

```

# Answer
I can't tell exactly what you are trying, it looks like you might just not have Traefik and the services on the same network.

Its also helpful to have a domain that's going to resolve to 127.0.0.1 on wildcard queries.

This might be a valuable starting point as a working example.

```
networks:
  traefik:
    name: demo_traefik

services:

  proxy:
    image: traefik:latest
    command: >
      --accesslog=true
      --api.insecure=true
      --log.level=DEBUG
      --providers.docker=true
      --providers.docker.network=demo_traefik
    ports:
    - "80:80"
    - "8080:8080"
    networks:
    - traefik
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    labels:
      traefik.http.routers.demo_traefik.rule: Host(`traefik.localtest.me`)
      traefik.http.services.demo_traefik.loadbalancer.server.port: 8080

  example:
    image: nginx
    networks:
    - traefik
    scale: 4
    labels:
      traefik.http.routers.demo_nginx.rule: Host(`example.localtest.me`)
      traefik.http.services.demo_nginx.loadbalancer.server.port: 80

  whoami:
    image: traefik/whoami
    networks:
    - traefik
    labels:
      traefik.http.middlewares.whoami_strip.stripprefix.prefixes: /whoami
      traefik.http.routers.whoami.rule: Host(`example.localtest.me`) && PathPrefix(`/whoami`)
      traefik.http.routers.whoami.middlewares: whoami_strip

```

`docker compose up` and then visit http://example.localtest.me/whoami in your browser.
> 0 votes

---
Tags: docker, docker-compose, networking, traefik
---


# Question
Title: What is a good strategy to prevent Ansible playbook runs against the wrong hosts?
It is too easy to run playbooks on the wrong hosts in Ansible

I know the best practice would be to use --limit to make sure you can not select the wrong host. I do not trust --limit to ensure Ansible runs playbooks only on the intended hosts.

Is it a crazy idea to use firewalld to disable communication to all the systems you do not want to update? Is there a more logical way to accomplish the same thing?

# Answer
> 1 votes
Q: ***"Disable communication to all the systems you do not want to update."***

A: The only safe way is to physically isolate such environment. A firewall might be an option. But, it's not feasible if you want to keep ssh or other connections that Ansible might use.

On the configuration level, there are many options.

**1) Special user**

Create a special user for this purpose on the systems you want to update. For example user *ansible\_update*. Depending on your environment configure the DEFAULT\_REMOTE\_USER to *ansible\_update*. This way you make sure no other systems can be connected by mistake.

In addition to this, you control who can connect to these systems by putting their public keys into the *authorized\_keys* of the user *ansible\_update* at the remote hosts.

To enforce this you have to:

* monitor users at the remote hosts and their *authorized\_keys*
* scan your project (playbooks, roles, inventory, configuration) for remote users other than *ansible\_update*

**2) Bastion host**

A better option is creating a bastion host and making it the only source of the configuration for the environment.

**3) ansible-pull**

The most flexible option is configuring the remote hosts to pull their updates on their own.

**Conclusion**: Create special users, create a bastion host, and make the remote hosts pull the updates from it.

# Answer
> 0 votes
If you enable firewalld rule for ansible, how you want to disable it? Yeah, there are ways, but hey! we talk here about having some sense in the work.

Where is your environment? I assume it is not dynamic, as for dynamic environment you use dynamic inventory.

First idea - split hosts per environments and corresponding directories. This way you have to provide the correct env and file. It gives the time to think.

Not-very-good-solution - run ansible through script. Makefile, bash, whatever, with confirm action.

The best - use CI/CD. Of course, you can do the mistake there, but... only once ;)

# Answer
> 0 votes
If you are really paranoid, generate a custom inventory containing only the hosts you want to update, and pass that.

# Answer
> 0 votes
I think you might be approaching the problem backwards and are using "hosts: all" instead of specific groups, then limiting with --limit. But if not, here's a solution I've used to target specific hosts (such as those in their maintenance window) within an existing group.

I start running against `hosts: all`

Then I find some sort of limiting criteria like, use the url module to query my ticketing system to tell me which devices have open changes for patching or something.

Then I use "add\_host" to create a temporary subgroup\*

```
- name: Add a host alias that we reach through a tunnel (Ansible 2.0 and newer)
  ansible.builtin.add_host:
    ansible_host: '{{ inventory_hostname }}'
    groups: subgroup

```

and I run against `hosts: subgroup`

\*warning if you refresh your inventory, this will get hosed

---
Tags: ansible, ansible-inventory, firewall
---


title: Set umask for an individual salt state

text:
# Question
Title: Set umask for an individual salt state
Is there a way to set the umask for the pip state module or is there a more generic way to set the umask before specific state modules are run? In ansible the pip module takes a umask parameter. I do not see an equivalent option in the salt pip state module. We run salt-call with a umask of 007 but we need to install certain python packages with more open permissions; is there a way to do this?

# Answer
## Edit update April 3rd 2023:

As of salt 3006 (https://salt.tips/whats-new-in-salt-sulfur/#umask) umask is now a global state argument and can be specified on any state.

## Original work around for pre 3006

I ended up working around this by creating a custom state module that wraps any state that I want to set the umask for:

\_states/umask.py:

```
import os

def wrap(wrapped_state, mask, *args, **kwargs):
    old_umask = None
    try:
        if not __opts__["test"]:
            old_umask = os.umask(int(mask, base=8))
        return __states__[wrapped_state](*args, **kwargs)
    finally:
        if old_umask is not None:
            os.umask(old_umask)

```

Usage:

```
"install python requests package":
  umask.wrap:
    - wrapped_state: pip.installed
    - mask: '022'
    - name: requests

```
> 2 votes

# Answer
**This answer is for versions \<3006**

No, there's no facility for changing the umask of the running Salt process.

What you could do is start a new process with `cmd.run`:

```
install python module:
  cmd.run:
    - name: pip install foo
    - umask: '077'
    - unless:
      - fun: pip.is_installed
        pkgname: foo

install python module at version:
  cmd.run:
    - name: pip install bar==4.2
    - umask: '077'
    - unless:
      - pip freeze | grep bar==4.2

```
> 1 votes

---
Tags: salt
---


# Question
Title: Is there a way to exclusively manage multiple ssh keys with differing per-key options using ansible?
Ansible provides a ansible.builtin.authorized\_key module which provides a lot of functionality:

* You can set `exclusive: true` to delete all other keys.
* You can set `key_options: ...`.
* You can list multiple keys in `key` by separating them with new lines.

Is there a way to combine all of the above?

The naive approach results in the `key_options` to be applied to all keys rather than having key options per key.

Is this a case of generating `authorized_keys` using `ansible.builtin.file` given the exclusiveness?

# Answer
One approach would be to use multiple authorized keys files, authorized\_keys2 is deprecated but there's no reason you can't use it and you can specify multiple authorized keys files in sshd config

> ```
> AuthorizedKeysFile
>
>      Specifies the file that contains the public keys used for
>      user authentication.  The format is described in the
>      AUTHORIZED_KEYS FILE FORMAT section of sshd(8).  Arguments
>      to AuthorizedKeysFile accept the tokens described in the
>      TOKENS section.  After expansion, AuthorizedKeysFile is
>      taken to be an absolute path or one relative to the user's
>      home directory.  Multiple files may be listed, separated by
>      whitespace.  Alternately this option may be set to none to
>      skip checking for user keys in files.  The default is
>      ".ssh/authorized_keys .ssh/authorized_keys2".
>
> ```

this might not be the optimal solution to your problem, but I think you're going to have to hack on ansible yourself to get it to do what you want.
> 1 votes

# Answer
The `#ansible` IRC channel noted that key options can be included in the multiline `key` field. When doing so, `key_options` can be left unset and things work.

Having to construct this multiline `key` field including options is pretty close to generating content for `ansible.builtin.file`. A minor benefit of doing this is that `ansible.builtin.authorized_key` actually parses the content and errors out when it does not parse before deploying it.
> 1 votes

---
Tags: ansible, ssh, key-management
---


# Question
Title: How to create, but not overwrite, a file and manage its permissions with ansible?
The task seems simple. If the file does not exist, create it, otherwise retain the file and its content. In both cases, apply permissions (`owner`, `group`, `mode`).

The most obvious candidate to this task is `ansible.builtin.file` with `state: touch`. However, it always appears as changed as the times need to be updated. Rather, once it exists and modes are ok, it should just be ok.

The next candidate likely is `ansible.builtin.copy`. If passing `force: false`, it creates the file. However, it does not fix up permission on an already existing file.

# Answer
> 3 votes
> *The most obvious candidate to this task is `ansible.builtin.file` with `state: touch`.*

Right, this could be an option.

> *However, it always appears as changed as the times need to be updated.*

According the documentation `file` module - Parameters not necessarily since `access_time` and `modification_time`

> *Should be `preserve` when no modification is required*

The following minimal example

```
---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

  - name: Create file
    file:
      path: "/home/{{ ansible_user }}/test.file"
      owner: "{{ ansible_user }}"
      group: "users"
      access_time: preserve
      modification_time: preserve
      state: touch

  - name: Touch again
    file:
      path: "/home/{{ ansible_user }}/test.file"
      owner: "{{ ansible_user }}"
      group: "users"
      access_time: preserve
      modification_time: preserve
      state: touch

```

will result into an output of

```
TASK [Create file] ***************************
changed: [localhost]

TASK [Touch again] ***************************
ok: [localhost]

PLAY RECAP ***********************************
localhost                  : ok=2    changed=1

```

---
Tags: ansible
---


title: How to lock a user using ansible?

text:
# Question
Title: How to lock a user using ansible?
Given a username, if that user exists, lock it, otherwise keep it missing.

The most likely module is `ansible.builtin.user`. There passing `password: "*"` and `shell: "/usr/sbin/nologin"` mostly achieves the lock behavior, but it also creates the user. The `state` property only has possible values `present` and `absent`, neither of which describes the desired behavior.

One can obtain a fact on the user presence using `ansible.builtin.getent` and then conditionally use `ansible.builtin.user`. Is there a better way?

# Answer
> 2 votes
> *... mostly achieves the lock behavior, but it also creates the user. The `state` property only has possible values `present` and `absent` ...*

Right, that would be the best approach and expected behavior.

> *One can obtain a fact on the user presence using `ansible.builtin.getent` and then conditionally use `ansible.builtin.user`.*

And also right, this would be too the recommended approach.

In other words, currently there is no possibility to configure such within one single task and if not using `shell` module, custom scripts or custom modules.

**Similar Q&A**

---
Tags: ansible
---


# Question
Title: How do you back up Jenkins jobs & master configs?
I'd like to backup all Jenkins jobs and config files. What's the easiest way of doing it?

# Answer
> 48 votes
There are many ways to do this but the easiest way I can think is doing a backup of the Jenkins Home folder.

You can see where is your Jenkins home with:

```
echo $JENKINS_HOME

```

And for example, if you only want to backup the jobs you can go to:

```
cd $JENKINS_HOME/jobs

```

And make a backup for that folder.

All that configuration will be a bunch of **XML** files.

If you are using the official Jenkins docker image, the home will be on:

```
/var/jenkins_home

```

# Answer
> 40 votes
All jobs (`jobs/`) and master config files (`config.xml`) can be found in Jenkins home folder (`JENKINS_HOME` ) in the following structure:

```
JENKINS_HOME
 +- config.xml     (jenkins root configuration)
 +- *.xml          (other site-wide configuration files)
 +- userContent    (files in this directory will be served under your http://server/userContent/)
 +- fingerprints   (stores fingerprint records)
 +- plugins        (stores plugins)
 +- workspace (working directory for the version control system)
     +- [JOBNAME] (sub directory for each job)
 +- jobs
     +- [JOBNAME]      (sub directory for each job)
         +- config.xml     (job configuration file)
         +- latest         (symbolic link to the last successful build)
         +- builds
             +- [BUILD_ID]     (for each build)
                 +- build.xml      (build result summary)
                 +- log            (log file)
                 +- changelog.xml  (change log)

```

Most of the config are in XML format, so backing all `.xml` files should be enough.

> All the settings, build logs, artifact archives are stored under the JENKINS\_HOME directory. Simply archive this directory to make a back up. Similarly, restoring the data is just replacing the contents of the JENKINS\_HOME directory from a back up.
>
> Back ups can be taken without stopping the server, but when you restore, please do stop the server.

---

For consistent backups it is good practise to keep `JENKINS_HOME` directory under Git repository.

For example:

```
cd $JENKINS_HOME
git init
shopt -s globstar
git add **/config.xml
git commit -m'Added job config files' -a

```

and pushing the files to the external repository. You can also add the following `.gitignore` file to ignore some files.

Related: Is there a way to keep Hudson / Jenkins configuration files in source control?

# Answer
> 11 votes
If your Jenkins jobs are defined in a Jenkinsfile you can store it in a git repository and have it loaded up by using Pipeline.

Unfortunately, since not all Jenkins plugins support Jenkinsfile and Pipeline, you will need to manually create new Jenkinsfiles if you wish to move existing jobs to this format.

# Answer
> 9 votes
The SCM Sync Configuration Plugin does exactly what you wish. Works with either svn or git to backup your jenkins core and job configuration, so gives you easy tracking as to who made changes, as well as a backup.

# Answer
> 6 votes
There are few ways to backup jenkins data and master configurations. The best way for backup is to use the Thinbackup plugin. You can schedule timely backups using cron expressions. You can configure full backup and incremental backup as well.

Another way to backup data and config is to take the disk snapshot of your jenkins master server. The ideal way to do this by mounting a disk and link the jenkins config directory to the disk mount point

Both the scenarios are well explained in this blog post. You will get a better idea and steps for the configurations.

# Answer
> 6 votes
I'm using scripts from `sue445/jenkins-backup-script`.

It archives Jenkins settings and plugins such as:

* `$JENKINS_HOME/*.xml`
* `$JENKINS_HOME/jobs/*/*.xml`
* `$JENKINS_HOME/nodes/*`
* `$JENKINS_HOME/plugins/*.jpi`
* `$JENKINS_HOME/secrets/*`
* `$JENKINS_HOME/users/*`

### Usage

```
./jenkins-backup.sh /path/to/jenkins_home archive.tar.gz

# add timestamp suffix
./jenkins-backup.sh /path/to/jenkins_home backup_`date +"%Y%m%d%H%M%S"`.tar.gz

```

# Answer
> 4 votes
You can try the thinBackup plugin (even though it is not actively maintained) \[if taking a *logical* backup is all you want\] (i.e. most of the config xml files, jobs, nodes etc). The backup size won't be huge.

# Answer
> 2 votes
I needed to migrate a Jenkins from one Windows Server instance to another. Finally I managed to do it like that:

* Stop the Jenkins service (if you can afford it)
* Copy the entire Jenkins folder (by default `C:\Program Files x86\Jenkins`)
* Paste onto the new instance
* Go inside the directory and run `jenkins.exe install`

This will register the freshly pasted Jenkins as a service on the new machine and will work 100% the same.

If this works then if you need a backup just for future safety, copy the Jenkins folder somewhere. It will work like a snapshot.

# Answer
> 0 votes
I summarized how to backup Jenkins using file system snapshots and find this method the most effective and secure.

---
Tags: jenkins, backup, linux
---


# Question
Title: Options to build a production server as a solo python developer?
I'm new to DevOps and overwhelmed with all the options.

I write python web applications as a solo developer, on my local machine. I have a "staging" server and I have multiple websites under different subdomains (eg. myapp.staging.mywebsite.dev). I use git on my local machine and use branches to create multiple versions of my apps and then I use git to push my code to this server so I can see how it looks on the web.

When I'm happy with my web app I want to be able to deploy it to a separate production server, so I can get real users using my apps. I could just use git to push my code to a new server but are there any other options that will help me create a live site?

# Answer
> 0 votes
One option that you could consider is using a continuous deployment tool like Jenkins, Travis CI, or GitLab CI. These tools can automatically deploy your code to a production server whenever you push your code to a certain branch in your git repository. This can save you the time and effort of manually deploying your code to your production server every time you make a change.

Another option is to use a service like Heroku, which makes it easy to deploy and manage your web applications. With Heroku, you can simply push your code to a git repository, and Heroku will automatically build and deploy your application.

Ultimately, the best option will depend on your specific needs and preferences, so it may be worth experimenting with different approaches to see what works best for you.

---
Tags: python, servers
---