# Question
Title: docker-credential-desktop.exe not installed
Moving from `Docker Desktop for Windows` to `Docker Server / CLI for Linux` to escape the license fee, I used the standard documentation for Ubuntu to install docker into my `WSL2`.

After frankensteining it that way, `docker` itself seemed to run okay, but `docker-compose` was broken.

```
user@COMPUTER:~/git/project/rest_backend$ docker-compose up --build
Pulling postgres (gitlab-int.company.de/team/dependency_proxy/containers/postgres:latest)...
Traceback (most recent call last):
  File "bin/docker-compose", line 6, in <module>
  File "compose/cli/main.py", line 72, in main
  File "compose/cli/main.py", line 128, in perform_command
  File "compose/cli/main.py", line 1077, in up
  File "compose/cli/main.py", line 1073, in up
  File "compose/project.py", line 548, in up
  File "compose/service.py", line 361, in ensure_image_exists
  File "compose/service.py", line 1250, in pull
  File "compose/progress_stream.py", line 102, in get_digest_from_pull
  File "compose/service.py", line 1215, in _do_pull
  File "site-packages/docker/api/image.py", line 396, in pull
  File "site-packages/docker/auth.py", line 48, in get_config_header
  File "site-packages/docker/auth.py", line 324, in resolve_authconfig
  File "site-packages/docker/auth.py", line 235, in resolve_authconfig
  File "site-packages/docker/auth.py", line 262, in _resolve_authconfig_credstore
  File "site-packages/docker/auth.py", line 287, in _get_store_instance
  File "site-packages/docker/credentials/store.py", line 25, in __init__
docker.credentials.errors.InitializationError: docker-credential-desktop.exe not installed or not available in PATH
[323] Failed to execute script docker-compose

```

How to fix this error?

# Answer
When you uninstall `Docker Desktop for Windows`, you lose all `exe` files - including `docker-credential-desktop.exe`. But you still need a credentials-store for the `docker login` part.

As written in the docs there are several alternatives.

I found, that `pass` works. The D-BUS plugin seems to be easier to configure, but apparently requires a graphical interface.

So download `docker-credential-pass-vx.y.z-amd64.tar.gz` from the Docker's git repo, extract it (`tar xvf <file>`), put it in your path like `sudo mv docker-credential-pass /usr/local/bin/`, make sure it is executable (`chmod a+x docker-credential-pass`) and test it with `docker-credential-pass list`. It requires you to have a configured instance of `pass` \- test with `pass list`.

Then check the docker-config at `$HOME/.docker/config.json` to make sure it uses `pass`:

```
  "credsStore": "pass"

```

That made my escape from the license-fee complete.
> 2 votes

---
Tags: docker, linux
---


# Question
Title: Is it good or ok or a bad practice to add Dependency via a RUN command in Dockerfile?
I am trying to create an image using a multi-stage build for a node project. I am using NestJs for the project since it uses TypeScript, and if I install only production dependency in the production stage it will not install NestJs CLI. Now, NestJs CLI is required to compile all the TypeScipt code to JavaScript. Most of the people or the blogs I have read, what they do is copy the output folder (compiled code from TypeScript to JavaScript) in the production stage which I don't want to do and really don't like the idea of copying the output folder because if I run only production stage via compose or a container it will fail.

Now, I have two options, either I can move the NestJs CLI as dependencies required for production in my package.json file, or I can add NestJs CLI via a RUN command in my Dockerfile, I want to know what would be right or the best way to do it.

# Answer
I would do this in the `Dockerfile`, as the NextJs CLI will be a hard dependency for the application. It should be exclusively defined in the `Dockerfile`. This way we can pin a version of NextJs CLI. Another bright side to this is that all similar application can now end up having the same `Dockerfile` and any changes to the NextJs version will now be an *image change* instead of an *application change*.
> 1 votes

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


# Question
Title: Allow / white list confirmation from internal target
Would it be sensible to use a ping from an internal site to an allow listed IP and detect the return to test that the allow list is working? That would assume there is a ping service at the other end to respond.

# Answer
> 1 votes
This just sounds like normal monitoring to me, so yeah it makes sense. You can use things like prometheus (free/open source) to do this (with an exporter).

Prometheus can keep a time series history and alert on the results (if they degrade). Alerts can be sent to things like slack or pager-duty (so you can get a phone call or message immediately if it stops working).

Lots of paid services exist for this too obviously.

---
Tags: ip
---


# Question
Title: Azure Pipeline Ubuntu 20.04 agent not picking up jobs
I took over admin of our dev environment, found out our Azure Pipelines Build Agent is running on the computer of an employee that quit, under his name. Trying to get a pipeline running on an Unbuntu box we have. Also, last time I touched Linux was in college about 15 years ago.

Running systemctl status shows that the Agent is active (running), but it isn't picking up any jobs.

I have done enough research to learn that the new Agent is missing Capabilities. MSBuild, Node, VisualStudio, SqlPackage, and more.

What I can't figure out is how to add those Capabilities to the Linux Agent. If it helps, we are deploying EF Core 3.1, Angular 12, Vue 3, and using EF Migrations.

# Answer
> 1 votes
I hit this question trying desperately to figure out why Visual Studio wasn't appearing as a capability.

It turns out my installation of Visual Studio on the build machine required a restart.

However because I has installed the Azure Pipeline agent *before* restarting the machine, the capability wasn't registered with Azure DevOps, so subsequent restarts didn't help.

I had to uninstall the azure pipelines agent from the build machine and remove the agent from my pool. When I reinstalled the agent (after a reboot of the machine) then the Visual Studio capability was present.

# Answer
> 0 votes
Broadly speaking, you add capabilities by installing software on the agent server. For example to get the Node capability, you should install Node.js.

Note that the way the capability is recognised is by environment variables; so you need to make sure that, after installing Node.js, there is an environment variable called *Node*, so the agent will know that it does have this capability.

---
Tags: azure-pipelines, ubuntu
---


# Question
Title: Ingress and liveness probes unable to connect to pod, but works via port-forward
I'm having a really strange issue with a particular application that's using the same Helm chart as many other apps in our cluster, and all the others are working fine.

The pods are running the application fine, I can port-forward to any pod, or the service, and see the app locally.

However when I try connecting to it from the ingress via the internet, I get a 502 error from NGINX. Even stranger, when I add liveness and readiness probes to the deployment, those are unable to connect either.

Again, this app uses the exact same Helm chart and config as many other apps that are working, and I can't find anything that's different about it between any other application. Somehow, the pods work but the cluster is unable to reach them internally. What could cause one particular deployment to act this way?

# Answer
> 0 votes
If the application listens on loopback only by default it's ports couldn't be accessible by other pods. port-forward works because it ignores IP addresses and kubelet makes a proxy.

---
Tags: kubernetes
---


# Question
Title: Contradictory output from ps -all after starting a docker container multiple times?
I'm having trouble understanding the output of `docker ps -all` after starting the same docker container multiple times (because there is a problem with my understanding of docker).

To illustrate the issue:

1. I create a docker container by issuing: `docker create busybox date` which returns something like `b48a2a768679dd5cdb767d24f6632d6c3d37f735596bf2b5e47517b495d641af`
2. Next I do the following:

```
$ docker start -a b48a2a768679dd5cdb767d24f6632d6c3d37f735596bf2b5e47517b495d641af
Sat Jan 22 03:14:24 UTC 2022

$ docker start -a b48a2a768679dd5cdb767d24f6632d6c3d37f735596bf2b5e47517b495d641af
Sat Jan 22 03:14:26 UTC 2022

$ sleep 20

$ docker start -a b48a2a768679dd5cdb767d24f6632d6c3d37f735596bf2b5e47517b495d641af
Sat Jan 22 03:14:53 UTC 2022

$ docker ps -all
CONTAINER ID   IMAGE     COMMAND   CREATED              STATUS                     PORTS     NAMES
b48a2a768679   busybox   "date"    About a minute ago   Exited (0) 4 seconds ago             sad_robinson

```

Now I see two problems with the docker `ps -all` output:

1. I think I should list all my instances of docker start -- since the output was different, I reckon each was a different start of the same container (as you can see I only see one row in the `ps -all` output)
2. The output from `ps -all` seems to list the first start as I ran all of these commands right after the other and other than the sleep command all of them returned immediately yet the output of `ps -all` reflects a start time of "about a minute ago"

# Answer
> 1 votes
The `docker ps` command lists containers, and the `docker start` command does not create new containers, so running it multiple times will not add additional entries to the `ps` output. Instead, what the `start` is doing is taking a non-running container and running it. The same would happen automatically with a restart policy on the container. The status in the `ps` output is the most recent status. Starting the container changes that status, as does stopping the container.

To create a new container that would be listed in `ps`, that's `docker container create`, or just `docker create`, which makes the container without starting it. Typically, people just use `docker run` which is a combination of `docker create` and `docker start` to create new containers.

---
Tags: docker
---


title: default backend - 404

text:
# Question
Title: default backend - 404
I am currently running a small K3S cluster in order to get familiar with K8S.

I am able to set up pods with ordinary LoadBalancers and get it to work without any problem. However, when I try to get it to work with Ingresses (HAProxy in my case) - I only end up with "default backend -404".

This is the deployment of the pods, based on the default NGINX container:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: notesncrap
  labels:
    app: notesncrap
spec:
  replicas: 2
  selector:
    matchLabels:
      app: notesncrap
  template:
    metadata:
      labels:
        app: notesncrap
    spec:
      containers:
      - name: notesncrap
        image: jselea/notesncrap
        ports:
        - containerPort: 80

```

I have also created a Service:

```
apiVersion: v1
kind: Service
metadata:
  name: notesncrap
  labels:
    app: notesncrap
spec:
  ports:
    - port: 80
  selector:
    app: notesncrap
    tier: frontend

```

And now the Ingress:

```
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: notesncrap
spec:
  rules:
  - host: k8scrap.selea.se
    http:
      paths:
      - path: /
        backend:
          serviceName: notesncrap
          servicePort: 80

```

I have the understanding that the name and label should be consistent over the .yaml files, and I personally can't see anything really wrong with what I have written.

Thankful for any pointers

EDIT:

As pointed out by the comments - the Ingress is behind a Apache Reverseproxy:

```
ProxyPass "/" "http://x.x.x.x:80"
ProxyPassReverse "/" "http://x.x.x.x:80"
ProxyRequests On
ProxyPreserveHost On

```

When I try curl directly against the ingress:

```
╭─root@sshgateway ~
╰─➤  curl -H "Host:k8scrap.selea.se" http://x.x.x.x
default backend - 404#

```

# Answer
Apparently - I forgot annotations and ingressclass:

I first added this:

```
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
  generation: 1
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: haproxy
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: haproxy-ingress-controller
  name: haproxy
spec:
  controller: haproxy.org/ingress-controller

```

And in the ingress:

```
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: notesncrap
  annotations:
    kubernetes.io/ingress.class: "haproxy"
  generation: 1
spec:
  rules:
  - host: k8scrap.selea.se
    http:
      paths:
      - path: /
        backend:
          serviceName: notesncrap
          servicePort: 80

```

Please observe the annotation.
> 0 votes

---
Tags: ingress, rancher
---


# Question
Title: Where does multi-role variable goes in Ansible?
There are multiple kind of variables in Ansible. And I find it overwhelming to wrap my head around them. Some of them are:

* The one we can write in roles//vars/main.yml
* The one we can write in the tasks file itself.
* Then there are group\_vars.
* Then we have host\_vars.
* There are also vars files.

**My use case is**... I have three roles. Namely nginx, jenkins and certbot. Thing common in all of them is the domain name. I decided to use a variable named {{ fqdn }} in all of those for sake of refactoring.

I am not able to decide on which version to use.

**What I want is**... ability to input the `fqdn` from command line when playbook is running. There should be default value which I can put somewhere in the repo.

# Answer
See Variable precedence: Where should I put a variable?. You can see that the role's defaults represent the lowest precedence for variables and the extra variables, declared on the command-line, override everything. There are a plethora of options between these two options.

For testing, create the roles and the playbook below. For example

```
shell> tree roles/
roles/
├── certbot
│   ├── defaults
│   │   └── main.yml
│   └── tasks
│       └── main.yml
├── jenkins
│   ├── defaults
│   │   └── main.yml
│   └── tasks
│       └── main.yml
└── nginx
    ├── defaults
    │   └── main.yml
    └── tasks
        └── main.yml

9 directories, 6 files

```

There are only two files in each role. The files are identical in all roles

```
shell> cat roles/certbot/defaults/main.yml
fqdn: "{{ fqdn_default|default('srv.example.com') }}"

shell> cat roles/certbot/tasks/main.yml
- debug:
    var: fqdn

```

Then, the playbook below

```
shell> cat playbook.yml
- hosts: localhost
  roles:
    - certbot
    - jenkins
    - nginx

```

gives as expected

```
shell> ansible-playbook playbook.yml

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

TASK [certbot : debug] ***************************************************
ok: [localhost] =>
  fqdn: srv.example.com

TASK [jenkins : debug] ***************************************************
ok: [localhost] =>
  fqdn: srv.example.com

TASK [nginx : debug] *****************************************************
ok: [localhost] =>
  fqdn: srv.example.com

```

In this example, the default values of *fqdn* in all roles are the same. Of course, you can declare different default values for each role if you want to.

---

You can declare the variable on the command-line

```
shell> ansible-playbook playbook.yml -e fqdn=www.example.com

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

TASK [certbot : debug] ***************************************************
ok: [localhost] =>
  fqdn: www.example.com

TASK [jenkins : debug] ***************************************************
ok: [localhost] =>
  fqdn: www.example.com

TASK [nginx : debug] *****************************************************
ok: [localhost] =>
  fqdn: www.example.com

```

---

Moreover, in this example, you can also change the default value, e.g. in the *group\_vars*

```
shell> cat group_vars/all.yml
fqdn_default: default.example.com

```

Then the playbook will use the value of *fqdn\_default*

```
shell> ansible-playbook playbook.yml

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

TASK [certbot : debug] ****************************************************
ok: [localhost] =>
  fqdn: default.example.com

TASK [jenkins : debug] ****************************************************
ok: [localhost] =>
  fqdn: default.example.com

TASK [nginx : debug] ******************************************************
ok: [localhost] =>
  fqdn: default.example.com

```

---

Use vars\_prompts if you want to `input the fqdn from the command line when the playbook is running`. e.g.

```
shell> cat playbook.yml
- hosts: localhost
  vars_prompt:
    - name: fqdn
      prompt: What is the fqdn?
      private: no
  roles:
    - certbot
    - jenkins
    - nginx

```

```
shell> ansible-playbook playbook.yml
What is the fqdn?: ww9.example.com

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

TASK [certbot : debug] ************************************************
ok: [localhost] =>
  fqdn: ww9.example.com

TASK [jenkins : debug] *************************************************
ok: [localhost] =>
  fqdn: ww9.example.com

TASK [nginx : debug] ***************************************************
ok: [localhost] =>
  fqdn: ww9.example.com

```

Quoting from the Note: "*Prompts for individual vars\_prompt variables will be skipped for any variable that is already defined through the command line --extra-vars option,...*"
> 3 votes

---
Tags: jenkins, ansible, nginx, certbot
---


# Question
Title: Is it possible to store your state for different Terraform Workspaces separately?
Let's say I have a terraform project with a production and development workspace. Is it possible to store the development workspace elsewhere so I don't have to give the admin the ability to run commands that mess up production?

I'm basing this question on the *"Terraform: Up & Running, 2nd Edition"* book by Yevgeniy Brikman which calls this a "drawback". From Page 93,

> The state files for all of your workspaces are stored in the same backend (e.g., the same S3 bucket). That means you use the same authentication and access controls for all the workspaces, which is one major reason workspaces are an unsuitable mechanism for isolating environments (e.g., isolating staging from production).

Are there any tools to help address this following with the above quote, is there anyway to store the state for different workspaces in different S3 buckets? Or, is the only option to forgo Terraform workspaces entirely.

# Answer
This is possible and I just completed a migration at my company. We originally had all our state for all workspaces in a centralized s3 bucket.

We now have a separate s3 bucket per workspace, and in our case each workspace is tied directly to an aws account.

To do this you have to pass in back end settings dynamically at the time of terraform init. We do this in a centralized pipeline template so it is handled for the developers automatically and it goes to the correct location.

Here is the docs on how to pass in these settings at the time of terraform init.

https://www.terraform.io/language/settings/backends/configuration#command-line-key-value-pairs

Let me know if you have any questions on this.
> 3 votes

---
Tags: terraform, terraform-workspace
---


title: decode base64 Github Secrets

text:
# Question
Title: decode base64 Github Secrets
I am setting up a pipeline to run Cypress automated tests using github actions/workflows on my code anytime there is a push to the repo. I came into a scenario where I want to generate dyanmic .env files depending on the branch , so instead of hard coding variables i created a base64 string and saved that as an secret and accessed that secret inside the code, however when i try to decode i run into issues, let me show you my code

**ci.yml**

```
name: Nuxt CI Pipeline
    on:
      push:
        branches: [ Cypress-reconfigure ]
      # pull_request:
      #   branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [ 14.x ]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v2
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - name: Generating .env files
      env:
        STAGING_ENV_FILE: ${{ secrets.STAGING_ENV_FILE }}
        PRODUCTION_ENV_FILE: ${{ secrets.PRODUCTION_ENV_FILE }}
      run: |
        [ "$GITHUB_REF_NAME" = Cypress-reconfigure ] && echo $STAGING_ENV_FILE | base64 --decode > .env
        [ "$GITHUB_REF_NAME" = staging ] && echo $PRODUCTION_ENV_FILE | base64 --decode > .env
    - run: cat .env
    - run: npm ci
    - run: npm run cy:ci

```

**Screenshot**

I followed this answer which was best suited for my scenario Stack Overflow post

As you can see, the error doesnt say anything it just exists! I have very limited knowledge of Devops can someone help me out with what I am doing wrong?

# Answer
> 2 votes
This is guaranteed to always fail:

```
      run: |
        [ "$GITHUB_REF_NAME" = Cypress-reconfigure ] && echo $STAGING_ENV_FILE | base64 --decode > .env
        [ "$GITHUB_REF_NAME" = staging ] && echo $PRODUCTION_ENV_FILE | base64 --decode > .env

```

Why? Depending on the value of `$GITHUB_REF_NAME` only one of the lines will run. But the other line will return a non-zero return code:

```
$ [ "a" = "b" ] && true

$ echo $?
1

```

And GHA is configured to abort on the first command that doesn't return a zero exit code (that's the successful exit code).

To fix, you should use an if-then, rather than the shell one-liner:

```
      run: |
        if [ "$GITHUB_REF_NAME" = Cypress-reconfigure ]; then echo $STAGING_ENV_FILE | base64 --decode > .env; fi
        if [ "$GITHUB_REF_NAME" = staging ]; then echo $PRODUCTION_ENV_FILE | base64 --decode > .env; fi

```

---

Note that I didn't include a different workaround in the shell command of ignoring errors with a `|| true`:

```
[ "$GITHUB_REF_NAME" = Cypress-reconfigure ] && echo $STAGING_ENV_FILE | base64 --decode > .env || true

```

because it results in false positives if the command (e.g. `base64 --decode`) fails.

---
Tags: continuous-integration, github, github-actions
---


# Question
Title: DevOps Roadmap: Underststanding OS Concepts
According to the DevOps Roadmap from roadmap.sh, understanding the following OS topics are recommended:

* Process Management
* Threads and Concurrency
* Sockets
* POSIX Basics
* Networking Concepts
* I/O Management
* Virtualization
* Memory/Storage
* File Systems

Are there recommended materials on these topics? It would be good to compile resources and classes (perhaps from coursera, udemy, EdX etc.)

# Answer
I haven't taken this course, but perhaps this EdX course Computer Hardware and Operating Systems from NYU might be a good starting place.

Current outline is:

* Week 1 - Fundamentals of system hardware
* Week 2 - Introduction to OS concepts
* Week 3 - Processes & threads
* Week 4 - Thread concurrency and deadlocks
* Week 5 - Memory management
* Week 6 - Exam

Has explicit coursework for a number of the topics posed in my original question (3 by my count).
> 0 votes

---
Tags: learning
---


# Question
Title: TCP communication blocked during Pod termination in Kubernetes
I have a cluster running on AWS EKS, v1.20.7-eks-d88609

I have a Pod and a NodePort Service to expose it to the outside.

Some clients will connect to it through a TCP connection which will be kept alive.

However, I was trying to configure a graceful termination of the connection when the Pod was terminated, by capturing the SIGTERM and sending a final message in the TCP connection telling the clients to disconnect.

Problem is these final TCP packets (sent after the SIGTERM is detected) never arrive at the destination.

I have run a tcpdump inside the Pod and confirmed that the packet is being sent correctly: https://i.stack.imgur.com/eW53z.jpg

But it does not arrive at the destination (where I had another tcpdump to check this)

TCP even tries to retransmit the packet since an ack for it didn't arrive, but none of them are able to reach the destination.

I was not able to reproduce this in a local Minikube cluster running same version of Kubernetes (1.20.7). Things worked well in this local cluster.

I'm not sure the best way to debug this in the AWS EKS cluster. It seems to be some issue caused by something inside Kubernetes, since the app tries to send the packet.

# Answer
> 0 votes
I've found the problem after some time, will add an answer here in case someone finds this in the future.

Basically, my problem was exactly what is described in https://github.com/aws/amazon-vpc-cni-k8s/issues/1531

I had Calico installed in my cluster and was using a version that had a bug which blocked the Pod networking during the termination phase.

This was the tutorial I followed when I installed Calico: https://docs.aws.amazon.com/eks/latest/userguide/calico.html

All I had to do to fix the problem was to uninstall Calico and install it again using a newer version (by following this same tutorial again)

---

Additional tip:

One of the things that helped me debug this problem was to make sure my apps weren't the ones to blame on this behavior.

I did this by running tcpdump in the Pod and forwarding its output to a local Wireshark for visualization. See this: https://downey.io/blog/kubernetes-ephemeral-debug-container-tcpdump/

After I found out my apps were sending traffic correctly, I knew the problem was something inside Kubernetes and started looking for possible culprits.

---
Tags: kubernetes
---


# Question
Title: What are the reasons AWS EC2 status check fails?
I have an instance on AWS free tier `t3.micro`.

The problem I faced is suddenly my instance was not able to connect with other instances.

I have checked on the dashboard and see that on the status check column it was showing `1/2` checks passed while another instance is `2/2` passed

On the Alarm status column, it was showing `1/2` in alarm.

I check on alarm details and it was showing a green tick on CPU utilization while the red triangle icon is showing on status check failed.

I also check the monitoring of the instance and found that the status checks failed graph has 1 count.

I have restarted the machine and now it is `2/2` passed.

What are the reasons AWS EC2 status check fails?

# Answer
> 1 votes
Here, you can find a full list of reasons why status checks fail and how can you enable alarms too which can initiate recovery.

https://aws.amazon.com/premiumsupport/knowledge-center/ec2-linux-status-check-failure/

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


# Question
Title: Connect external Jenkins Master to GKE with Kubernetes plugin
I find the documentation at https://github.com/jenkinsci/kubernetes-plugin quite unclear when it comes to step by step configuration of external Jenkins master.

What are the exact steps that need to be followed? I have installed the Kubernetes plugin and I have tried to supply some cluster info, but I have got lost there.

For Name I have taken the output from kubectl config view --raw, specifically the context for the given cluster and the cluster name part.

For Kubernetes URL I have set the IP address from the Server field in the same output from above.

Kubernetes server certificate key - for this part I have initially tried to follow the same pattern from above and take the value of the certificate-authority-data field, but I got an "Error testing connection https://XX.XXX.XXX.XX: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input", so I have attempted to convert that value with echo "the field value here" | base64 -d \> ca.crt and use that, but it failed again and I have also got it form the UI for GKE show cluster ceritficate section, all of them give me failure on testing connection with the error from above.

I couldn't really go past this point, but I see everything being quite unclear forward, so I would appreciate a step-by-step recommendation or any guide that I am missing.

# Answer
It looks like you are missing the service account configurations bit. Refer to : https://devopscube.com/jenkins-build-agents-kubernetes/

> If your Jenkins server is running outside the Kubernetes cluster, you need to specify the following.
>
> 1. Kubernetes URL: This is the Kubernete master API endpoint. If is it https enabled, use the https url.
> 2. Kubernete Server Certificate key: If you have a the Kubernetes Cluster CA certificate, you can add it for secure connectivity. You can get the certificate from the pod location /var/run/secrets/kubernetes.io/serviceaccount/ca.crt .If you dont have the certificate, you can enable the “disable https certificate check” option.
> 3. Credentials: For Jenkins to communitcate with the Kubernetes cluster, we need a service account token with permissions to deploy pods in the devops-tools namespace.
> 1 votes

# Answer
You could install Jenkins using helm to install the k8s plugin as well.

https://github.com/helm/charts/tree/master/stable/jenkins
> -1 votes

---
Tags: jenkins, kubernetes, cicd
---


# Question
Title: Jenkins: Stagger triggering of next pipeline steps
I have a daily Jenkins trigger job that sets off a bunch of CI jobs based on a cron timer. All the daily jobs are set off by this trigger job, the daily job itself doesn't do anything.

However, this causes a bit of a load on the infrastructure available when all these jobs start executing all at once. Is there any way to stagger the triggering of these next steps in the pipeline over a period of time?

# Answer
Refer to the answer here if that helps: https://stackoverflow.com/a/12472740

There is a `H` parameter in the cron and you can also set a range in time for the `H` parameter: https://github.com/jenkinsci/jenkins/blob/master/core/src/main/resources/hudson/triggers/TimerTrigger/help-spec.jelly#L47
> 1 votes

# Answer
I'd take a look at throttling your concurrent builds to reduce load:

https://plugins.jenkins.io/throttle-concurrents/
> 0 votes

# Answer
This is an example of a thundering herd issue.

A common way to deal with this issue is to sleep for a random amount of time (known as "splay") at the beginning of the job. This spreads out the load over the splay period.
> 0 votes

---
Tags: jenkins, jenkins-plugins, jenkinsfile
---


# Question
Title: Jenkins: Permission issue using Docker as build environment
I installed Jenkins on an Ubuntu 16.04 machine. The Jenkins itself is not run in a container. What I want to do is simply call `yarn install` using a node image. So here is my Jenkinsfile:

```
pipeline {
    agent any
    stages {
        stage('install node modules...') {
            agent { docker 'node' }
            steps {
                sh 'cd /path/to/package.json; yarn install'
            }
        }
    }
}

```

Pretty straightforward, right?

jenkins user/group is `112:116`, and the uid of the node container is `1000`, hence yarn process (which is run as node user 1000) can't do its things, like `mkdir /.config`.

I tried to spin up the node container passing in argument `-u 1000`, it bumped into permission issues when trying to create durable directories.

It looks like one or the other kind of issue, how can I work around that?

Jenkins logs:

Below is where the build starts and fails.

```
[Pipeline] sh
[Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2] Running shell script
+ docker inspect -f . node
.
[Pipeline] withDockerContainer
Jenkins does not seem to be running inside a container
$ docker run -t -d -u 112:116 -w /var/lib/jenkins/workspace/Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2 -v /var/lib/jenkins/workspace/Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2:/var/lib/jenkins/workspace/Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2:rw,z -v /var/lib/jenkins/workspace/Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2@tmp:/var/lib/jenkins/workspace/Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2@tmp:rw,z -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** --entrypoint cat node
[Pipeline] {
[Pipeline] sh
[Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2] Running shell script
+ cd /path/to/package.json
+ yarn install
yarn install v0.24.6
error An unexpected error occurred: "EACCES: permission denied, mkdir '/.config'".
info If you think this is a bug, please open a bug report with the information provided in "/var/lib/jenkins/workspace/Pipeline_Test_Jenkins_test-4JTFYMX7KSJY6ZH44VINNGEB7WH2D2HWYZN5ABF6O32O2HBQJYXQ@2/<path>/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
[Pipeline] }
$ docker stop --time=1 c1147934ea689f71a449e486282db03338b12182368def31bdf8e8cf179ab46a
$ docker rm -f c1147934ea689f71a449e486282db03338b12182368def31bdf8e8cf179ab46a
[Pipeline] // withDockerContainer
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 1
Finished: FAILURE

```

# Answer
I had the same issue with node. The thing is files in the container are owned by "root:root". Try adding docker args `-u root:root`:

```
docker {
    image 'node:8'
    args '-u root:root'
}

```
> 14 votes

# Answer
I just had a similar issue today, although with another image.

```
docker {
 image 'node:8'
 args '--tmpfs /.config'
}

```

Reference: https://docs.docker.com/storage/tmpfs/ This way you shouldn't be worried about any security leaks or files which are present after the container is destroyed inside the jenkins.
> 4 votes

# Answer
`buildEnv.inside("-u 0") {}` resolved my problem. But then the workspace will contains directory and files owned by root which can not be deleted by the user Jenkins at the next run when cleaning the workpace , so I have added `sh "sudo chown jenkins: -R \$PWD/"` at the beginning of the pipeline.
> 4 votes

# Answer
This worked for me:

```
docker {
  image 'node'
  args '-e HOME=/tmp/home'
}

```

/tmp is writable for everyone.
> 1 votes

---
Tags: jenkins, docker, jenkins-pipeline
---


# Question
Title: My Python application doesn't communicate with MySQL inside docker. Can someone help me?
The connection is not succeeding in docker. Look at my settings:

Dockerfile

```
FROM python:3.8.5-alpine

WORKDIR /app

COPY requirements.txt .

RUN python3 -m pip install --upgrade pip

RUN pip install -r requirements.txt

COPY . .

CMD ["python3", "-m", "scraper"]

```

docker-compose.yml

```
   version: '3'
    services:
      python_app:
        build:
          context: .
          dockerfile: Dockerfile
        ports:
          - '80:80'
        links:
          - 'mysql_db'
        depends_on:
          - mysql_db
        networks:
          - app-tier

      mysql_db:
        image: mysql:5.7
        ports:
          - '3307:3306'
        environment:
          MYSQL_ROOT_PASSWORD: 'flavio'
          MYSQL_DATABASE: 'Vestibular'
          MYSQL_USER: 'flavio'
          MYSQL_PASSWORD: ''
        networks:
          - app-tier

    networks:
      app-tier:
        driver: bridge

```

db.py

```
import mysql.connector

def insert_into_database(data):
    print("Salvando no banco de dados")
    aux = ""
    for i, item in enumerate(data):
        if i == len(data)-1:
            aux += str(item)
        else:
            aux += f"{str(item)}, "

    try:
        connection = mysql.connector.connect(host='localhost',
                                            database='Vestibular',
                                            user='flavio',
                                            password='')
        cursor = connection.cursor()

        stmt = "SHOW TABLES LIKE 'Candidates'"
        cursor.execute(stmt)
        result = cursor.fetchone()

        mySql_Create_Table_Query = """CREATE TABLE Candidates (
                             Id int(11) AUTO_INCREMENT NOT NULL,
                             Name varchar(250) NOT NULL,
                             Score varchar(250) NOT NULL,
                             PRIMARY KEY (Id)) """

        mySql_insert_query = f"""INSERT INTO Candidates (Name, Score)
                            VALUES
                            {aux}; """

        if not result:
            cursor.execute(mySql_Create_Table_Query)
        cursor.execute(mySql_insert_query)
        connection.commit()
        print(cursor.rowcount, "Record inserted successfully into Candidates table")
        cursor.close()

    except mysql.connector.Error as error:
        print("Failed to insert record into Candidates table {}".format(error))

    finally:
        if connection.is_connected():
            connection.close()
            print("MySQL connection is closed")

```

# Answer
The `python_app` and `mysql_db` services/containers do not share a network namespace, thus they don't have the same `localhost`. Just use `mysql_db` as the hostname when connecting to the DB.

I would recommend that your python code takes the DB hostname from an env var or command line argument. If you want to hardcode it, you can use something like `db` and then use the docker compose links aliasing feature which is documented here to map `db` to the actual service name.
> 1 votes

---
Tags: docker, docker-compose, dockerfile, python, mysql
---


# Question
Title: How do I set metadata of a blob from inside a Python Google Cloud Function? Test fails with "blob.size = 99 AttributeError: can't set attribute"
I try to add the rowcount to the metadata of the Google Cloud Storage file from inside the Python Google Cloud Function.

I follow the official Cloud Storage Docs example of "Edit object metadata" by just trying to change an attribute the same way as in the code:

```
from google.cloud import storage

def set_blob_metadata(bucket_name, blob_name):
    """Set a blob's metadata."""
    # bucket_name = 'your-bucket-name'
    # blob_name = 'your-object-name'

    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.get_blob(blob_name)
    metadata = {'color': 'Red', 'name': 'Test'}
    blob.metadata = metadata
    blob.patch()

    print("The metadata for the blob {} is {}".format(blob.name, blob.metadata))

```

My code, just setting one attribute:

```
from os import environ
from google.cloud import storage

    ...
    storage_client = storage.Client()
    bucket = storage_client.bucket(environ["BUCKET_NAME"])
    # Retrieve a blob, and its metadata, from Google Cloud Storage.
    # Note that `get_blob` differs from `Bucket.blob`, which does not
    # make an HTTP request.
    blob = bucket.get_blob(environ["FILE_NAME_TEST"])
    print("Size: {} bytes".format(blob.size))
    print("Custom Time: {}".format(blob.custom_time))
    blob.size = 99

```

But this throws an error in the logs:

```
blob.size = 99 AttributeError: can't set attribute"

```

How to write to an attribute using the Python google\_cloud\_storage package?

# Answer
It may be obvious from the example, but I did not get it. I thought that "metadata" would be all of your metadata and that you could overwrite it as you like, so that `{'color': 'Red', 'name': 'Test'}` would actually replace the whole metadata at hand.

I even created

```
    blob.metadata = {
        **metadata,
        **{
            "rowcount": 99,
            "columncount": 55
        },
    }

```

to join the filled metadata with the additional attributes. But this is of course not needed. And you also cannot overwrite any default attributes of the metadata either.

If you want to save something in the metadata, you *must* add them as dictionary to the "metadata" attribute.

In my case, when I want to store the rowcount, I just need:

```
def set_blob_metadata(bucket_name, blob_name):
    """Set a blob's metadata."""
    # bucket_name = 'your-bucket-name'
    # blob_name = 'your-object-name'

    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.get_blob(blob_name)
    metadata = {'rowcount': 555}
    blob.metadata = metadata
    blob.patch()

    print("The metadata for the blob {} is {}".format(blob.name, blob.metadata))

```

#### Wrap up

I thought at first that the `metadata` attribute is just all metadata in one attribute as a dictionary, but instead, it is None by default and you can fill it with a dictionary of your choice to add new attributes. Only this "metadata" attribute can be filled at all, any other attribute throws `AttributeError: can't set attribute"`.
> 0 votes

---
Tags: google-cloud-platform, google-cloud-storage
---


title: Names field in docker ps -a command

text:
# Question
Title: Names field in docker ps -a command
When I run the "docker ps -a" command following command I fields:

```
CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS                      PORTS               NAMES
d69c6f81b591        paigeeworld/centos7   "/bin/bash"         10 minutes ago      Exited (0) 10 minutes ago                       sweet_curran

```

If I try to do a "docker run -it sweet\_curran bash" I get an "unable to find image" error. What the "Names" field used for if I cannot use it to run the image?

# Answer
If you don't name a container when you run it Docker will make up a random name for you. This is handy for differentiating different invocations of a container without resorting to hex values. You can see by checking the source all of the possible names that could be generated.
> 1 votes

# Answer
Run is used for running a new container.

Exec is used for doing something inside of an existing container.

```
docker exec -it <container_id_or_name> echo "I'm inside the container!"

```

So, when you use `exec`, you can use the container name from your running container, as shown in our output.
> 0 votes

---
Tags: docker
---


# Question
Title: What is the proper AWS IAM policy for access to a single bucket that allows stacking?
I am working on a buildout where I am doing the following. Eventually I will need to make this scalable so I am not doing this manually each time.

I have several clients dumping data into S3 buckets. Each client needs R/W access to just that bucket. For that, I can use this policy

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "BucketOperations",
            "Effect": "Allow",
            "Action": "s3:ListBucket*",
            "Resource": "arn:aws:s3:::<bucketname>"
        },
        {
            "Sid": "ObjectOperations",
            "Effect": "Allow",
            "Action": [
               "s3:AbortMultipartUpload",
               "s3:DeleteObject*",
               "s3:GetObject*",
               "s3:PutObject*"
            ],
            "Resource": "arn:aws:s3:::<bucketname>/*"
        },
        {
            "Sid": "DenyAllOthers",
            "Effect": "Deny",
            "Action": "s3:*",
            "NotResource": [
               "arn:aws:s3:::<bucketname>",
               "arn:aws:s3:::<bucketname>/*"
            ]
        }
    ]
}

```

On my end, I have several analysts that are using Athena to query the data via Tableau and other tools. I have a Glue job to index the source bucket, and each client dataset will need a Athena results bucket so I can maintain appropriate access.

My problem is that I don't know how to write the S3 policy so that I can have one-per-bucket, and then attach them to the IAM users. When I use the above policy to create

* bucket1-policy
* bucket2-policy

And then add them to an IAM user, eg

* bucket1-policy
* bucket2-policy
* my-athena-policy
* ...

it looks like `DenyAllOthers` parts are causing the user to not have S3 access.

Is there a better way to write the S3 access policy, so I can have one per bucket, or do I need to have a separate policy for my Athena users to grant access to the two buckets and then deny the rest?

# Answer
> 1 votes
Let's start at the end: *it looks like DenyAllOthers parts are causing the user to not have S3 access.*

Indeed:

> **By default, all requests are denied**. (In general, requests made using the AWS account root user credentials for resources in the account are always allowed.)

> An explicit allow in any permissions policy (**identity-based or resource-based**) overrides this default.

> The existence of an Organizations SCP, IAM permissions boundary, or a session policy overrides the allow. If one or more of these policy types exists, they must all allow the request. Otherwise, it is implicitly denied.

> **An explicit deny in any policy overrides any allows.**

https://docs.aws.amazon.com/IAM/latest/UserGuide/intro-structure.html

That means that it is OK to not have any `Deny` rule. That would work for the customers.

I would suggest `Deny` `s3:PutObjectAcl` with anything else then bucket-owner-full-control - see an example here https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html

An alternative - just disable public access on the whole bucket with `PublicAccessBlockConfiguration` https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-publicaccessblockconfiguration.html

Speaking of that - creating accounts for the users via CloudFormation template allows you to pass the bucket name as a parameter. That way you can manage many users even with just PowerShell / unix sh or similar. You would have one template in a repo and you can change the permissions on a list of users with a simple loop. Terraform (suggested by one of the comments) or any other automation tool is also an option, usually the tools do use CloudFormation under the hood, so it may be still a good idea to understand CloudFormation just in case somethings does not work and you have to investigate. Or to made sure that some configuration option of your automation tool did not allow much broader permissions that you assume.

I also suggest to name the buckets in a clever way. If you name the upload buckets for example upload- you can allow read access to all the upload buckets by one rule with `arn:aws:s3:::upload-*/*`.

For your your analysts - create a group for them, add the permissions to the group.

It is good to know that you can put the IAM policy either on a bucket or on an identity (role/user/group...). Sometimes it does not matter, sometimes it does. If you ever need to allow access to a customer based on their AWS account, you will need to use a resource policy on the bucket. On the other side - maintaining a complex resource policy with many updates may be challenging. As an alternative you can also allow to assume roles.

---
Tags: amazon-web-services, amazon-s3, aws-iam
---


# Question
Title: Jenkins error using Junit plugin: Test reports were found but none of them are new. Did LeafNodes run?
I'm trying to get our test reports (generated using google test with the xml output switch) into Jenkins, but keep getting the error message:

`Test reports were found but none of them are new. Did leafNodes run?`

Jenkins says the test xml files are 15s old, which means these must have been generated on this test run.

We're using a declarative pipeline, and the TEST stage looks like:

```
stage("TEST") {
  steps {
    dir("${BUILD_ROOT}") {
      sh "make test_report_clean test || true"
      junit keepLongStdio: true, testResults: '*_test_gcov.xml'
    }
  }
}

```

Here the `test_report_clean` make target deletes any existing xml reports, and the `test` target is generated from cmake's `add_test` function. I have verified that test reports are being generated in the correct location by looking in the Jenkins workspace.

I've also tried the xunit plugin, but the same error message is produced!

(This question was originally posted to Super User but I was asked to move it.)

# Answer
I would recommend cleaning the workspace on each run, this should ensure you're not running into old files in the workspace. You'll want to run this as a post build step, meaning it runs regardless of the build status.

There's a pretty decent thread here too for a more detailed explanation when it comes to declarative and the Workspace Cleanup plugin:

```
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
    post {
        always {
            cleanWs()
        }
    }
}

```

https://stackoverflow.com/questions/37468455/jenkins-pipeline-wipe-out-workspace
> 0 votes

---
Tags: jenkins
---


# Question
Title: Terraform workspaces vs isolated directories?
I'm reading the *"Terraform: Up & Running, 2nd Edition"* book by Yevgeniy Brikman, the author is going through a lot of work to *NOT* use workspaces? Is this sound? It seems like really esoteric. His reasoning is as follows:

> *"The state files for all of your workspaces are stored in the same backend \[...\] Workspaces are not visible in the code or on the terminal unless you run `terraform workspace` \[...\] Putting the two previous items together, the result is that workspaces can be fairly error prone."*

As to the second point, why not just add the workspace to your your PS1 if that's an issue? Using something like ZSH/PowerLevel10k, my prompt shows Terraform workspace information.

As far as the first point, I broke that off into separate question.

Is there anything else that I'm missing in this workspace vs directories for isolation.

# Answer
Workspaces are an unnecessary complexity which causes the possibility that you destroy your prod environment (or leak secrets). It is a much better practice to switch backends, and that is noted in the docs:
https://www.terraform.io/language/state/workspaces

> In particular, organizations commonly want to create a strong separation between multiple deployments of the same infrastructure serving different development stages (e.g. staging vs. production) or different internal teams. In this case, the backend used for each deployment often belongs to that deployment, with different credentials and access controls. Named workspaces are not a suitable isolation mechanism for this scenario.
>
> **Instead, use one or more re-usable modules to represent the common elements, and then represent each instance as a separate configuration that instantiates those common elements in the context of a different backend.** In that case, the root module of each configuration will consist only of a backend configuration and a small number of module blocks whose arguments describe any small differences between the deployments.

The new hotness is a backend file, which you can choose at init:
https://www.terraform.io/language/settings/backends/configuration#file
> 1 votes

# Answer
Digging down further into the book, the author picks this back up on page 304.

> **...a 1:1 representation...** If I browse your *live* repository, I should be able to see, from a quick scan, what resources have been deployed in what environments. That is, **every resource should have a 1:1 match with some line of code checked into the live repo.** This sems obvious at first glance, but it's surprisingly easy to get wrong. \[...\] A more subtle way to get it wrong is to use Terraform workspaces to manage environments, so that the live infrastructure is there, but the code isn't. **That is, if you use workspaces your live repo will have only one copy of the code, even though you may have 3 or 30 environments deployed with it. From merely looking at the code, there will be no way to know what is actually deployed**, which will lead to mistakes and make maintenance complicated. Therefore, as described in "Isolation via Workspaces" on page 88, instead of using workspaces to manage environments, **you want each environment defined in a seperate folder, using separate files, so that you can see exactly what environments have been deployed just by browsing the *live* repository.**

So it seems one of the author's scruples though described as *"not visible in the code or on the terminal"* is more general and extends to tooling (like web svc browsers, ex., GitHub) which do not support Terraform workspaces. The author wants to know where the code deployed without pulling it down. Such that he can see what is on development and production without using a "workspace".

He later extends this to the entirety of Git branching which is slightly more bizarre, because his problem there is even smaller (pg 304),

> Unfortunately, \[branching\] only solves part of the problem. Even though the Terraform backends provide locking for Terraform state, they cannot help you with locking at the level of the Terraform code itself. **In particular if two team members are deploying the same code to the same environment but from different branches, you'll run into conflicts that locking can't prevent.**

But sure, certainly *"deploying the same code to the same environment but from different branches"* sounds lke a real bad idea.
> 0 votes

---
Tags: terraform, deployment, terraform-workspace
---


# Question
Title: docker exec and docker run do not work with names
I ran docker run busybox a few times with success.

```
docker run busybox echo "hello from busybox"

```

Output:

```
hello from busybox

```

docker ps -a shows the following:

```
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                         PORTS               NAMES
59be6eaee13e        busybox             "echo 'hello from bu…"   2 minutes ago       Exited (0) 2 minutes ago                           lucid_ride
2d1a63cfd696        busybox             "echo 'hello from bu…"   4 minutes ago       Exited (0) 4 minutes ago                           quizzical_engelbart
69804c9b7db5        busybox             "echo 'hello from bu…"   49 minutes ago      Exited (0) 49 minutes ago                          focused_clarke
65c371540c5d        busybox             "echo 'hello from bu…"   59 minutes ago      Exited (0) 59 minutes ago                          charming_merkle
2fc6bd074048        busybox             "sh"                     About an hour ago   Exited (0) About an hour ago                       nice_noyce

```

Trying to use either docker run or docker exec with the name in the Names column instead of the imange name busyboxy.

```
docker run lucid_ride echo "hello from lucid_ride"

```

Output:

```
docker: Error response from daemon: pull access denied for lucid_ride, repository does not exist...

```

Using exec:

```
docker exec -it lucid_ride echo "hello from lucid_ride"

```

Output:

```
Error response from daemon: Container 59be6eaee13e4089a5abcccee7fa4778f8b76332e15a0dc2f698057c0368f95f is not running

```

So, I can run docker run busybox all day and have instances show up in the results of the docker ps -a. But, when I try to use any of the names in the Names column (either with exec or run) it doesn't work. Why is this? Thank you.

# Answer
Here are a short description of the docker commands above :

* docker run : starts a docker container from the given image name ;
* docker exec : runs a program inside a running container;
* docker start : restart a stopped container by relaunching the initial command;

You should definitivly try the last one ;-)
> 1 votes

---
Tags: docker
---


# Question
Title: How to run short-lived command using kubectl
I was trying to measure pod startup time buy running the following:

```
% kubectl run --image busybox --attach test -- date
error: timed out waiting for the condition

```

At first it seems like this command takes a long time to start the pod. However if you run `kubectl get pods` while it is running you see something interesting.

At first the command succeeds:

```
% kubectl get pods
NAME   READY   STATUS      RESTARTS   AGE
test   0/1     Completed   0          2s

```

Then transitions to `CrashLoopBackOff`.

```
% kubectl get pods
NAME   READY   STATUS             RESTARTS   AGE
test   0/1     CrashLoopBackOff   1          7s

```

The logs show that the command ran successfully.

```
% kubectl logs test
Thu Jan 27 15:02:36 UTC 2022

```

It is unclear to me why the pod is transitioning from `Completed` to `CrashLoopBackOff`. Is there a way to make `kubectl` do the right thing in this scenario?

---

The best work-around I have found so far is to use a slower command and subtract the delay from my testing.

```
% kubectl run --image busybox --attach test -- sleep 10

```

# Answer
> 2 votes
Ah, shortly after posting I found a clean solution. Adding `--restart=Never` makes the command work as expected.

```
% time kubectl run -n kcox-test --image busybox --attach test --restart=Never -- date
Thu Jan 27 15:10:41 UTC 2022
time Total: 9.449 (1%), User: 0.100, System: 0.034  - kubectl run -n kcox-test --image busybox --attach test --restart=Never -- date

```

---
Tags: kubernetes, kubectl
---


# Question
Title: How to get exposed ports from inside of container?
I want to know which port(s) are exposed when user run the image.

```
docker run -p 1000:1234 myimagename

```

I want to get `1234` value in container since I will use it for some configurations(IIS bindings etc.) inside of container.

Is there any env variable for this purpose?

# Answer
> 1 votes
TL;DR: You don't.

From inside of the container, you do not know which ports are exposed since exposing a port is only documentation visible in the image and container metadata. To detect which ports are published, you'd need to know the host IP, which can be difficult to lookup depending on your environment, and then you'd need to do something like a port scan of the host and tcpdump inside the container to detect the incoming request. All of this is non-trivial because it's solving the problem in the wrong direction.

Instead you should build your app inside the container to listen on a specific port, configure that default port and potentially let users override it with a variable or config file. Then you document this decision be exposing the port in the Dockerfile with the `EXPOSE` command. This is only documentation, it goes in the image metadata, users and programs can see it, but by default docker will not do anything with it. Finally, users of your image will publish the port on the host when and where appropriate, and map to the port of your application.

In other words, the right side of the published port (the container port) is largely controlled by the image creator, not the user running the container. If they publish to the wrong port, it is not the applications responsibility inside the container to dynamically adjust what port it is listening on, and this would be difficult to impossible to do if you had multiple ports anyway.

If your application needs to be configured with the publicly reachable port (and probably IP or hostname), that should be injected as a configuration or environment variable. Trying to automate this from inside the container is error prone since your application may be exposed to users through a load balancer or NAT.

# Answer
> 1 votes
Tonight I decided to just query the docker api using a small express server running on the host node from within the container.

```
const express = require('express')
const app = express()
const port = 3000

var unirest = require('unirest');

app.get('/', (req, res) => {
    let id = req.query.id;

    if (!req.query.id) {
        res.send('I do not think you belong here.')
    } else {

        var Request = unirest.get('http://localhost:2375/containers/' + id + '/json');

        Request
            .header('Accept', 'application/json')
            .end(function (response) {
                console.log(response.body.NetworkSettings.Ports)
                res.send(response.body.NetworkSettings.Ports)

            })
    }
})

app.listen(port, () => {
    console.log(`app listening on port ${port}`)
})

```

Then simply query the webserver using curl inside of your container:

`curl 172.1.0.1:3000/?id=yourcontainersname`

The webserver will then respond with the ports exposed via docker for the name requested

The code may need tweaking of course for your needs but this worked out for me pretty well and I plan on expanding on this for myself a bit further.

For my purpose, I only need to grab one port number from the list of exposed ports so I can post configure some software automatically, here is it working :)

```
[user@exampleserver]# curl localhost:3000?id=342128351638585344
32902

```

Side note, to get the single port, I did this:

```
let responseKeys = Object.keys(response.body.NetworkSettings.Ports);
let selectedPort = responseKeys[3].replace("/tcp", "");
console.log(selectedPort)

```

I hope this idea helps someone at least

# Answer
> 0 votes
If you want to get the values in the container, You have to have either netcat or telnet or some other tools, to check what are the ports open in your container, and then try to poke that ports from the container to host.

`netstat -tnlp` will give you all open ports, only if you don't know what are the ports are supposed to have listened in the container `nc -zv (host ip) (port)` will tell you whether the port is published or not.

# Answer
> -1 votes
Please refer the below link You can use docker inspect for the same docker inspect

---
Tags: docker, containers, dockerfile
---


# Question
Title: Ansible network automation: log all commands from multiple plays
I'm trying to write a script to publish basic configurations for any new devices. Also to assert compliancy of basic configuration for devices in production.

Trying to gather all the lines executed, on each devices, coming from the different plays, that I call on a central one.

How to centralize the outputs, (the commands that ansible will execute) and possibly assemble it into one file?

Trying to gather the commands in check mode in order to confirm before execution.

# Answer
> 0 votes
As mentioned in Ansible: `lineinfile` for several lines?

```
- name: "create block in own file per host"
  blockinfile:
     path: "/dir/logs/{{ inventory_hostname }}.txt"
     create: true
     block: "some commands"
     ...

- name: "add more line in block (even if already executed on another host)"
  lineinfile:
     line: "{{ item }}"
     ...
  loop: "{{ more_commands_1 | default([]) +
    more_commands_2 | default([]) }}"

- name: "assemble all files in one"
  assemble:
    src: "/dir/logs/"
    dest: "/dir/logs/all_hosts.txt"
    ...

```

I used those modules along with `check_mode: false` and `delegate_to: localhost`.

Those are handlers (in a role). I notify them in each module that execute commands on a device.

Would be glad to use a more clever solution if it exists.

---
Tags: ansible, networking, infrastructure-as-code
---


# Question
Title: AllowedPattern for emails in Cloudformation template
I am struggling with specifying a regular expression for email parameter of Cloudformation :

```
Parameters:
  MyEmail :
    Type: String
    Description: Email for notifications
    AllowedPattern: /[^\s@]+@[^\s@]+\.[^\s@]+/
    ConstraintDescription: You should enter a valid email

```

As you see, I tried `/[^\s@]+@[^\s@]+\.[^\s@]+/` and it won't work.

What is the regular expression for emails in Cloudformation template ?

# Answer
> 5 votes
> **Important**
>
> Since AWS CloudFormation templates use the JSON syntax for specifying objects and data, you will need to add an additional backslash to any backslash characters in your regular expression, or JSON will interpret these as escape characters.
>
> For example, if you include a `\d` in your regular expression to match a digit character, you will need to write it as `\\d` in your JSON template.

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-regexes.html

The very same applies to your `\s` expressions. Use `\\s` and it works.

**EDIT:**

Looking back the question I started to wonder the missing quotation marks on your definition. I found out the expessions are yaml format that is the second way to define things in aws.

If you should follow the yaml syntax, the right way to give string values is like this:

```
AllowedPattern = '/[^\s@]+@[^\s@]+\.[^\s@]+/'

```

https://aws.amazon.com/blogs/aws/aws-cloudformation-update-yaml-cross-stack-references-simplified-substitution/

**EDIT:**

> Use quotes if your value includes special characters, (e.g. :, {, }, \[, \], ,, &, \*, #, ?, |, -, \<, \>, =, !, %, @, ).

https://stackoverflow.com/questions/19109912/do-i-need-quotes-for-strings-in-yaml

# Answer
> 1 votes
This worked for me in YAML format

```
Parameters:
  MyEmail:
    Description: Email for notifications
    Type: String
    AllowedPattern: '[^@]+@[^@]+\.[^@]+'

```

---
Tags: amazon-web-services, infrastructure-as-code
---


# Question
Title: How to apply DevOps with just one developer?
**Background:** I am a self-taught Java developer, focusing mostly on desktop JavaFX applications. I work for a large company and have developed a fairly large piece of software that is relied upon by my department of over 100 employees on a daily basis (it is our primary knowledge management suite of applications).

The software, which began as a hobby project as I was learning Java, has become "mission critical" to our company and I am still the sole developer building and maintaining it.

The entire development cycle for me would be coming up with ideas myself (I used to have another position in the company so the workflow was familiar to me), asking coworkers for input, and then deploying updates as I wished.

As a result of this ad hoc approach, the software (with over 60,000 lines of code) is poorly documented, buggy, and full of "amateur" code I used to "just make it work" as I was learning. I also still manually build and deploy each release (I do not use any build tools such as Maven). *I do use Git/GitHub for version control.*

**DevOps:** I have recently become a certified *SAFe 5 DevOps Practitioner* but I have not had the chance to put much of it into practice. I understand the core principles of Agile and have a very limited amount of experience working with it.

**Question:** As a developer who has always worked alone, how can I apply the DevOps methodology to my workflow? Without a team of developers to work with, every piece of the development lifecycle rests on me.

I have tried following the Agile principles of meeting with the software's users to better understand the business value and such, but there is a lot of old code that also needs to be corrected or improved, though the users do not usually contact me to submit a "user story" or request changes. There is just a lot of things I've known for a long time that need to be done.

Any insight would be greatly appreciated, but is DevOps even suited to a single developer environment?

# Answer
> 2 votes
I went through a similar path. Every time you touch your code do something in that direction. You zip your app manually? Do it via a shell script. Every time you see something you know you can express as code, do it. The technology does not matter. Over the time these steps will join together. For example - if you know how to unzip and set up your application on a production server, you can wrap it in something like AWS Code Deploy and next time you trigger the process from a command line. Then you add a git repo hook, etc... You will learn more along the way and you fill find solutions which you cannot see now. Every login you don't have to do, every mouse click which you do not do is a change for better. It will free your capacity for some other problem. It is also easier to redefine the pipeline with some higher level tools once you have code blocks which clearly state what steps are needed.

# Answer
> 0 votes
Devops will help you find bad code path or dependencies, which cause issues down the line.

As you are responsible for both sides of the coin(developer/OPs), you can Integrate lessons learnd as ops into your work as dev.

# Answer
> 0 votes
> I have tried following the Agile principles of meeting with the software's users to better understand the business value and such, but there is a lot of old code that also needs to be corrected or improved, though the users do not usually contact me to submit a "user story" or request changes. There is just a lot of things I've known for a long time that need to be done.

Do the users have a *platform* for reporting bugs or requesting changes ? I mean, something more formal than E-mail ? If not, it's something I would work on, and you can use the platform for **documentation** too.

I would also work on the **automation** of build & deployment since you've clearly identified this as a possible improvement. Try to automate as much as you can, especially the boring and time-consuming stuff.

DevOps is not just a process, it is a state of mind too.

One more suggestion: since you depicted your own software as buggy I would focus on improving **code quality** and reliability. Especially if this is a source of dissatisfaction or frustration - then it should be a priority.

For this add **monitoring tools** if you don't have any: collect application **logs**, investigate errors, fix them and update your code before the users come to you to report issues (if they even bother doing that). The idea is also to become more **proactive**, and communicate your improvement strategy toward your users.

---
Tags: cicd
---


# Question
Title: docker-compose does not update /etc/hosts at build time
When building an image of a docker container I need to access a service on host localhost.

It looks like `--add-host` option for `docker` command updates `/etc/hosts` both at image build time and container runtime.

The analogous option for `docker-compose` command, `extra_hosts` seems to work only at container runtime. How do I enable it at docker image build time?

Looks like there feature request for that: https://github.com/docker/compose/issues/7323, but not implemented yet. What would be workaround until this is solved?

# Minimal working example

Here's my `Dockerfile`:

```
FROM python:3.8-slim-buster
RUN grep "host.docker.internal" /etc/hosts || echo "Missing"
CMD grep "host.docker.internal" /etc/hosts || echo "Missing"

```

and `docker-compose.yml`:

```
version: "3.9"
services:
  test:
    build: .
    extra_hosts:
      - "host.docker.internal:host-gateway"

```

Running docker:

```
docker build . --add-host host.docker.internal:host-gateway  --no-cache -t test \
    && docker run --add-host host.docker.internal:host-gateway test

```

prints:

```
172.17.0.1      host.docker.internal
...
172.17.0.1      host.docker.internal
...

```

while:

```
docker-compose build --no-cache && docker-compose up

```

returns

```
Missing
...
test_1  | 172.17.0.1    host.docker.internal
...

```

# Motivation

I have a Flask app that depends on my private Python package that I install during docker image build. I store my private Python packages in my local devpi instance hosted on the same machine I use for building docker image. Hence, my Flask app `pyproject.toml` points to the devpi instance:

```
url = "http://localhost:3141/testuser/dev/+simple"

```

or rather

```
url = "http://host.docker.internal:3141/testuser/dev/+simple"

```

# Answer
The solution is to use Compose V2 and then:

```
docker compose build --no-cache && docker compose up

```

(note dashes replaced with spaces).

Here's specific line in implementation.
> 0 votes

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


# Question
Title: How do I configure SSH keys in a Vagrant multi-machine setup?
I have 4 VMs in my Vagrantfile - 3 application servers and an Ansible control host.

I only use Vagrant to create the VMs as I provision them manually from the ansible control host because I am still creating/editing the ansible scripts.

I can do `vagrant ssh ansible` and `vagrant ssh app1/2/3` etc. but when I try to do `ansible-playbook oracle.yml` from the Ansible control host, SSH fails with

```
fatal: [192.168.60.10]: UNREACHABLE! => {"changed": false, "msg": "SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue", "unreachable": true}

```

I can successfully ssh from the Ansible VM to the Oracle VM using user vagrant and password vagrant.

The key parts of my Vagrantfile are:

```
config.ssh.insert_key = false

config.vm.define "db" do |db|
    db.vm.box = "boxcutter/ol67"
    db.vm.hostname = "oracle-vm"
    db.vm.network "forwarded_port", guest: 22, host: 2201, id: "ssh", auto_correct: false
    db.vm.network "forwarded_port", guest: 1521, host: 1521
    db.vm.network "private_network", ip: "192.168.60.10"
    db.vm.provider "virtualbox" do |v|
        v.name = "oracle-vm"
        v.linked_clone = true
        v.memory = 2048
        v.cpus = 2
    end
end

#Optional ansible control machine for Windows users
config.vm.define "ansible", autostart: false do |ansible|
    ansible.vm.box = "williamyeh/ansible"
    ansible.vm.hostname = "ansible-vm"
    ansible.vm.network "forwarded_port", guest: 22, host: 2204, id: "ssh", auto_correct: false
    ansible.vm.network "private_network", ip: "192.168.60.50"
    ansible.vm.provider "virtualbox" do |v|
        v.linked_clone = true
    end
    #Mount the project directory on the guest so we can run the playbooks from there
    ansible.vm.synced_folder ".", "/data/ansible", create: true
end

```

What do I need to put in the Vagrantfile to allow the Ansible VM to connect to the other VMs without requiring a password or extra manual steps after `vagrant up`?

This is just for development testing on a private network on developers PCs so security is not really an issue and comes second to ease of implementation and smooth user experience.

# Answer
> 8 votes
Based on techraf's 3rd suggestion I did the following:

* `vagrant up ansible`
* `ssh-keygen` (no password just pressed `Enter`)
* copied `.ssh/id_rsa` and `.ssh/id_rsa.pub` to the project directory
* `vagrant destroy ansible`
* modified the `Vagrantfile` to copy the `id_rsa` to all hosts
* modified the `Vagrantfile` to copy the `id_rsa.pub` into `authorized_keys` on all hosts
* modified the Vagrantfile to disable host checking

Vagrantfile snippet:

```
 config.vm.provision "file", source: "id_rsa", destination: "/home/vagrant/.ssh/id_rsa"
 public_key = File.read("id_rsa.pub")
 config.vm.provision :shell, :inline =>"
     echo 'Copying ansible-vm public SSH Keys to the VM'
     mkdir -p /home/vagrant/.ssh
     chmod 700 /home/vagrant/.ssh
     echo '#{public_key}' >> /home/vagrant/.ssh/authorized_keys
     chmod -R 600 /home/vagrant/.ssh/authorized_keys
     echo 'Host 192.168.*.*' >> /home/vagrant/.ssh/config
     echo 'StrictHostKeyChecking no' >> /home/vagrant/.ssh/config
     echo 'UserKnownHostsFile /dev/null' >> /home/vagrant/.ssh/config
     chmod -R 600 /home/vagrant/.ssh/config
     ", privileged: false

```

# Answer
> 8 votes
There is no general method and it might depend on how `boxcutter/ol67` was packed.

1. The easiest method would be to define the password in the Ansible inventory file:

```
[oracle-vm:vars]
ansible_ssh_user=vagrant
ansible_ssh_pass=vagrant

```
2. The second method would be to leave the insecure private key configured on the `oracle-vm` machine and inject the private key to the `ansible` VM:

```
config.vm.provision "shell" do |s|
  ssh_insecure_key = File.readlines("#{Dir.home}/.vagrant.d/insecure_private_key").first.strip
  s.inline = <<-SHELL
    echo #{ssh_insecure_key} >> /home/vagrant/.ssh/id_rsa
    chown vagrant /home/vagrant/.ssh/id_rsa
    chmod 400 /home/vagrant/.ssh/id_rsa
  SHELL
end

```
3. Generate the key pair beforehand on the host machine, inject private key to Ansible VM, public key to Oracle's `authorized_keys`.
4. Generate the key pair on Ansible VM, copy the public key to Oracle VM using shell provisioner and inject `vagrant` as password for `ssh-copy-id`.

And the list does not end here, it depends on required security.

# Answer
> 0 votes
If you want to have a preformatted block within a list, indent by eight spaces:

1. generate public/private key

```
cd vagrant-home
ssh-keygen // just pressed enter
copy ~/.ssh/id_rsa .
copy ~/.ssh/id_rsa.pub .

```
2. edit Vagrantfile,add follow lines: config.vm.provision "file", source: "id\_rsa", destination: "/home/vagrant/.ssh/id\_rsa"

```
    public_key = File.read("id_rsa.pub")
    config.vm.provision "shell", inline: <<-SCRIPT
        chmod 600 /home/vagrant/.ssh/is_rsa
        echo 'Copying ansible-vm public SSH Keys to the VM'
        #mkdir -p /home/vagrant/.ssh
        chmod 700 /home/vagrant/.ssh
        echo '#{public_key}' >> /home/vagrant/.ssh/authorized_keys
        chmod -R 600 /home/vagrant/.ssh/authorized_keys
        echo 'Host 192.168.*.*' >> /home/vagrant/.ssh/config
        echo 'StrictHostKeyChecking no' >> /home/vagrant/.ssh/config
        echo 'UserKnownHostsFile /dev/null' >> /home/vagrant/.ssh/config
        chmod -R 600 /home/vagrant/.ssh/config
        SCRIPT

```
3. ```
        vagrant up // or vagrant reload --provision

```

# Answer
> 0 votes
You could generate the keys using shell provisioner ssh-keygen quiet mode, copy the pub key to the project folder and then copy it to the other(s) machine(s) using file provisioner. Assuming /vagrant/ is the project synced folder, it should be something like this:

```
machine1.vm.provision "shell", inline: "[ ! -f '/home/vagrant/.ssh/id_rsa' ] && ssh-keygen -q -f /home/vagrant/.ssh/id_rsa -N ''"

machine1.vm.provision "shell", inline: "cp /home/vagrant/.ssh/id_rsa.pub /vagrant/"

machine2.vm.provision "file", source: "id_rsa.pub", destination: "/home/vagrant/.ssh/"

machine2.vm.provision "shell", inline: "[ ! -f '/home/vagrant/.ssh/id_rsa_machine1.pub' ] && cat /vagrant/id_rsa.pub >> /home/vagrant/.ssh/authorized_keys"

machine2.vm.provision "file", source: "id_rsa.pub", destination: "/home/vagrant/.ssh/id_rsa_machine1.pub"

```

---
Tags: ansible, vagrant
---


# Question
Title: Shared Jenkinsfile for multiple pipelines (separate source repositories)
I'd like to write one Jenkinsfile to be shared between a number (~50) of pipelines/jobs, where each job handles the creation of a library from a specific source (git) repository.

Currently I have one job which uses SCons and build parameters to specify/calculate which repositories to build, but this involves cloning ~50 repositories each time and means features like the git change notes don't work (the repository with changes that is built isn't the repository containing the builder code, which typically just shows "No Changes").

Is there a better way to handle this situation? I see in this question (Modularizing CI/CD pipelines in Jenkins or in other tools?) that shared libraries are the suggested solution there, but whilst I can see that this simplifies the N Jenkinsfiles, it doesn't as far as I can tell reduce their number.

I'd like to avoid having any Jenkinsfiles in the source code repositories if possible (perhaps instead having information in the job configuration that boils down to "check out and run this Jenkinsfile from that other repository, as if it were in this one").

# Answer
> 1 votes
Putting Jenkinsfiles in every single repo is, as far as I can tell, unavoidable. As you mentioned in your question, you can use shared libraries to centralize the Pipeline code itself, but not the actual Jenkinsfiles, which will need to load/execute the shared library code.

The way I've dealt with this is to use external tools to enforce that all repositories contain a copy of a Jenkinsfile (which does nothing but load and execute the shared library code). For instance, our Terraform plan creates repositories from a template, and the template contains the aforementioned Jenkinsfile. We also use a tool called Thor during one of our build steps, and one of the tasks Thor performs is to synchronize certain files (including the Jenkinsfile, but also other files like licenses) to match a copy from a central repo. So whether I am creating a brand new repo or making changes to an existing one, there is always a tool to ensure that a simple Jenkinsfile is in place.

# Answer
> 1 votes
Try to put your base Jenkinsfile into Jenkins Shared Library. You can also make it parametric as a regular function. Please check out the following official document's related topic:

https://www.jenkins.io/doc/book/pipeline/shared-libraries/#defining-declarative-pipelines

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


# Question
Title: How to connect my host to Redis cluster network on docker-compose
I'm running this docker-compose.yaml on my machine (Mac with docker desktop) but am not able to connect the cluster with `redis-cli`.

I'm running it with

```
docker-compose up --build

```

I'm able to run `redis-cli` **from within the containers** like

```
❯ docker exec -it docker-redis-cluster_redis-1_1 redis-cli -c -p 7001                                                                                (eks-dev-blue/itamar)
127.0.0.1:7001> cluster nodes
c9c01ea75f43780f36f3dca445410c1c902bda0b 10.0.0.16:7006@17006 slave cc69a5c2467fff36daa62acefc70b4b49d7a22a6 0 1643633817569 2 connected
cc69a5c2467fff36daa62acefc70b4b49d7a22a6 10.0.0.12:7002@17002 master - 0 1643633816000 2 connected 5461-10922
9c1d48c16402c651578b4722ceb699aa0effa392 10.0.0.11:7001@17001 myself,master - 0 1643633816000 1 connected 0-5460
c83836c357ce77cf845cda983aa76aa7942e2489 10.0.0.14:7004@17004 slave 5bdf05a8d332646ee76ff0da64fb97570cf7117e 0 1643633816558 3 connected
5bdf05a8d332646ee76ff0da64fb97570cf7117e 10.0.0.13:7003@17003 master - 0 1643633817974 3 connected 10923-16383
115b037e3dc2de23389a3b085b4242b63bfa887a 10.0.0.15:7005@17005 slave 9c1d48c16402c651578b4722ceb699aa0effa392 0 1643633817000 1 connected

```

But I'm not able to communicate with the cluster from my host machine:

```
❯ redis-cli -c -h localhost -p 7001                                                                                (eks-prod-blue/prod)
127.0.0.1:7001> cluster nodes
Error: Server closed the connection

```

What am I missing? Is it a missing network\ports config?

# Answer
> 0 votes
You're creating the following network and your services get IPs from this range.

```
  redisnet:
    driver: bridge
    ipam:
      config:
        - subnet: 10.0.0.0/16

```

Which container are you connecting to? Does the IP get resolved correctly? Does your host machine know how to reach the 10.0.0.0/16 subnet? You need to have a entry in your route table that sends the traffic for 10.0.0.0/16 through the bridge adapter created for the `redisnet` network.

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


# Question
Title: Terraform get subnet id by it's CIDR block
I have a list of CIDRs for my subnets and want to get their ids. Is it possible to do with terraform?

```
my_subnets = ["212.12.1.0/24", "212.12.2.0/24", "212.12.3.0/24"]

```

I know VPC id as well, how to get an array of subnets ids via data source?

The idea is to pass that next as an argument to another module

```
vpc_options {
    # invalid code, just for illustration
    subnet_ids = data.aws_subnet.my_subnets[*].id
  }

```

# Answer
> 1 votes
It seems that you already know which CIDR ranges you wish to look up, and that you are trying to find the corresponding subnet id for each of them.

You can achieve that by using the `aws_subnet` data source with `for_each`, to tell Terraform to make a separate call to that data source for each of your CIDR ranges. I'm assuming that the `my_subnets` example in your question is inside a `locals` block and so it has declared and defined `local.my_subnets` to hold that list of strings.

```
data "aws_subnet" "example" {
  for_each = toset(local.my_subnets)

  cidr_block = each.key
}

```

A resource with `for_each` set appears in expressions as a map of objects where the map keys are the same as the `for_each` map keys (or, in this case, set elements). Therefore you can derive from this a mapping from CIDR block to subnet ID:

```
locals {
  subnet_ids = tomap({
    for cidr, subnet in data.aws_subnet.example : cidr => subnet.id
  })
}

```

or, if you don't actually care about the correspondence between the CIDR blocks and the ids and just want a flat set of ids, you can just ignore the instance keys:

```
locals {
  subnet_ids = toset([
    for subnet in data.aws_subnet.example : subnet.id
  ])
}

```

The second of these seems to be what is expected by the `subnet_ids` argument you want to assign to:

```
  vpc_options {
    subnet_ids = [
      for subnet in data.aws_subnet.example : subnet.id
    ]
  }

```

(I omitted the `toset` call when inlining this expression in the argument, because the schema for that `vpc_options` block will already tell Terraform whether `subnet_ids` is a set or a list, and so Terraform can convert automatically in that case.)

---
Tags: amazon-web-services, terraform, aws-vpc, terraform-module, aws-subnets
---


title: Terraform: apply only one tf file

text:
# Question
Title: Terraform: apply only one tf file
I have my security groups in a `securitygroup.tf` file.

In the same dir there are plenty of other resource descriptions (rds, ec2 etc).

Is there a way to perform a `terraform apply --auto-approve` **only** for my `securitygroups.tf`?

# Answer
> 58 votes
Not really. The standard way to work around this though is to use eg:

```
terraform apply -target=aws_security_group.my_sg

```

but that's only going to apply one security group at a time, so will get tedious if you have a lot of them. You can, however, target multiple resources in one command:

```
terraform apply -target=aws_security_group.my_sg -target=aws_security_group.my_2nd_sg

```

However, there are potentially a couple of workarounds:

* **The `-target` parameter respects dependencies.**

This means if you were to eg. `-target=aws_instance.my_server` and that instance had, say, five security groups attached to it via interpolation, changes to those security groups *should* be included in the plan (I haven't thoroughly tested this, but I believe this is how it works).

That is a bit messy though, as you probably don't want to touch an instance. A safer alternative might be using something like a `null_resource` to provide a target for the security groups, but again I haven't tried this (there might be another 'safe' resource you could rely on, though?).
* **Create a module.**

You can target a module just like you can target a plain resource (be sure to include the quotes around the target name):

```
 terraform apply -target="module.my_security_groups"

```

Inside this module, you could define all of your security groups - just like you would have outside of the module. As well as being able to target it directly, this also makes it easier for you to re-use the same set of security groups for other infrastructure, if you ever need to.

# Answer
> 14 votes
If you organize your code by modules, you could apply terraform only on a module, eg :

```
# securitygroup.tf
module "securitygroup" {
  source = "git@github.com:user/securitygroup-terraform-module.git?ref=master"
}

$ tf apply -target=module.securitygroup

```

# Answer
> 2 votes
Using terraform module is preferred, but if you really have to run terraform apply against a single file, I made this bash script to generate terraform apply command against all targets and modules in one file:

```
#!/usr/bin/env bash
if [[ -z "$@" ]]; then
  echo "Missing file input arguments"
  exit 1
fi

echo "terraform apply \\"
for FILE in "$@"
do
  RESOURCE=$(sed -n 's/resource "\([^"]*\)" "\([^"]*\)".*/-target=\1.\2 \\/gp' $FILE)
  MODULE=$(sed -n 's/module "\([^"]*\)".*/-target=module.\1 \\/gp' $FILE)
  if [[ -z "$RESOURCE" ]] && [[ -z "$MODULE" ]]; then
    echo "Cannot detect terraform resource and module in $FILE"
    exit 1
  fi

  if [[ ! -z "$RESOURCE" ]]; then
    echo -e $"$RESOURCE"
  fi
  if [[ ! -z "$MODULE" ]]; then
    echo -e $"$MODULE"
  fi
done
echo "-refresh=true"

```

I'm not really a bash expert, but it was tested to work on Mac.

EDIT: The sed command assumes that the resources and modules are formatted nicely according to `terraform fmt` like so:

```
resource "aws_eip" "my_public_ip" {
}

resource "aws_instance" "my_server" {
}

module "my_module" {
}

```

# Answer
> 2 votes
No, unfortunately, **Terraform** doesn't have the feature to apply **a specific .tf file**. **Terraform** applies **all .tf files** in the same directory.

But you can apply **the specific code** with **comment out** and **uncomment**. For example, you have 2 .tf files **"1st.tf"** and **"2nd.tf"** in the same directory to create the resources for **GCP(Google Cloud Platform)**:

Then, **"1st.tf"** has this code below:

```
provider "google" {
  credentials = file("myCredentials.json")
  project     = "myproject-113738"
  region      = "asia-northeast1"
}

resource "google_project_service" "project" {
  service = "iam.googleapis.com"
  disable_dependent_services = true
}

```

And **"2nd.tf"** has this code below:

```
resource "google_service_account" "service_account_1" {
  display_name = "Service Account 1"
  account_id   = "service-account-1"
}

resource "google_service_account" "service_account_2" {
  display_name = "Service Account 2"
  account_id   = "service-account-2"
}

```

Now, first, you want to only apply the code in **"1st.tf"** so you need to **comment out** the code in **"2nd.tf"**:

**1st.tf**:

```
provider "google" {
  credentials = file("myCredentials.json")
  project     = "myproject-113738"
  region      = "asia-northeast1"
}

resource "google_project_service" "project" {
  service = "iam.googleapis.com"
  disable_dependent_services = true
}

```

**2nd.tf (Comment Out)**:

```
# resource "google_service_account" "service_account_1" {
#   display_name = "Service Account 1"
#   account_id   = "service-account-1"
# }

# resource "google_service_account" "service_account_2" {
#   display_name = "Service Account 2"
#   account_id   = "service-account-2"
# }

```

Then, you apply:

```
terraform apply -auto-approve

```

Next, additionally, you want to apply the code in **"2nd.tf"** so you need to **uncomment** the code in **"2nd.tf"**:

**1st.tf**:

```
provider "google" {
  credentials = file("myCredentials.json")
  project     = "myproject-113738"
  region      = "asia-northeast1"
}

resource "google_project_service" "project" {
  service = "iam.googleapis.com"
  disable_dependent_services = true
}

```

**2nd.tf (Uncomment)**:

```
resource "google_service_account" "service_account_1" {
  display_name = "Service Account 1"
  account_id   = "service-account-1"
}

resource "google_service_account" "service_account_2" {
  display_name = "Service Account 2"
  account_id   = "service-account-2"
}

```

Then, you apply:

```
terraform apply -auto-approve

```

This way, you can apply **the specific code** with **comment out** and **uncomment**.

# Answer
> 1 votes
Doesn't look like it's possible. Here is the code to load config files and it loads all \*.tf files from current directory (or a specified one) and there is nothing there to limit the configuration to a single file.

---
Tags: terraform
---


# Question
Title: how to pull only git logs without pulling the whole file tree and diffs
I have a server that has limited storage space and I need to track a git repository, but I am only interested in the log messages and not the whole repository (blobs, diffs, tags, ...). the repository that I'm willing to track has a large commit history, and above that it stores some large binary files which makes it impossible to sync and pull everything.

now I'm wondering if there a way to pull only git logs from a branch!

and if possible is possible to pull logs after or before a commit hash?

# Answer
> 1 votes
If you interested only in the log messages, you don't need to pull. You could run:

```
git fetch

```

... and then

```
git log --remotes

```

Now you'll see remote commit logs.

To see only remote commits (assuming the branch in question is master):

```
git log --remotes --not master

```

If you can't even fetch, you'll need to ssh the remote repository machine. If you're using Github you could try use its API.

---
Tags: git
---


# Question
Title: What are the real world benefits of RDS instance (at rest) encryption?
AWS offers at rest encryption for its RDS instances. I think this *sounds* nice, and it's something that comes up regularly on security reviews but I'm not sure what the real benefit is. The most likely way someone will get access to my database is via my AWS account, which would nullify any benefits of KMS (unless it happens to be a user without access to that KMS key and without authorization to grant that access). In what realistic scenarios does this protect my company?

A similar question was asked several years ago over on Reddit, with this response:

> I've always understood it that this (and S3 encryption, etc) are mostly security theater. If a rogue Amazon employee grabbed a bunch of disks out of the racks and stole them, encryption would save you in this case. But it's unlikely for this scenario to ever happen, and even if it did, data is probably sharded across a bunch of physical disks and who knows if that employee would even get usable data even without encryption.
>
> But in the real world, HIPAA, PCI, or some other such compliance standard frequently requires that you use this, whether it's security theater or not. So you just enable it and move on with life.

I'm wondering if there are more updated views on this outside of marketing statements and regulatory/compliance concerns.

# Answer
This is a defense in depth tactic.

There are other defense mechanisms in place at AWS to prevent data leakage such as disk destruction on disposal or limiting access to data centers to approved employees. If those defense controls were to fail the encryption at rest would provide a layer of defense to prevent data leakage.

As you pointed out, access to your account provides access to the data. The defense in depth for this attack surface is that you keep your access keys secure, rotate them every 90 days, and don't provide access where it isn't need. Your user accounts should have strong passwords, no reuse, rotated every 90 days, the right access controls, and MFA enabled. These are all defense in depth tactics to keep your environment secure.

In general, from a non-AWS perspective, data at rest encryption could be the only layer of data leakage protection. Not everyone is SOC2/ISO27001/PCI/HIPAA compliant.

Bottom line, is data at rest encryption security theater? No. Is it the first line of defense? No (in the case of AWS). Is it part of a broader security defense in depth strategy? Yes.

References:
Defense in Depth Definition
Defense in Depth
> 1 votes

---
Tags: amazon-web-services, security, amazon-rds, encryption
---


title: Recommended starting guide on CICD

text:
# Question
Title: Recommended starting guide on CICD
I'm new to the community, and I looked around a bit but didn't find a good point to start from. I have a specific problem I want to solve, but while trying to think of a solution I realized I need a better devops background, and I couldn't find a resource to help me with that.

So, I'll lay out my specific question, and after that I'll summarize what are the main areas of knowledge I'm hoping to get a better understanding on...

I have a CI pipeline that works something like this:

1. Developer: push code to source control (bitbucket server)
2. Jenkins: poll SCM and run pipeline
3. Jenkins pipeline: build artifacts from code, set environment, and test (pytest)
4. Upon success and demand - manually pack the artifacts into a release

Now, most of the things here are done without any dedicated tools.

e.g.

1. python wheels are created but not stored anywhere (though I do have a dockerized `pypi` server - I just don't have an automated flow that uploads and updates the wheels there)
2. I want to have more artifacts, e.g. `deb`s, binaries, libraries, etc. (I now have them stored inside local storage) and I want them better stored, better sorted and maintained, and more accessible (thought of Jfrog artifactory here)
3. I want the entire environment creation to be handled by proper tools (called from the Jenkins pipeline?), and not scripts I've written (thought of `tox` for creating the python environment, but it's not enough, as I also need to be able to create docker environments, and I also need to control `dpkg` as I have `deb`s I create and install. Maybe `chef` or `ansible` can do the trick. \[I do use `ansible` from time to time to configure all hosts on my network, but that's basically for silly things like changing a few config files here and there\])

My general question is - is there a guidebook for how to create a proper CICD system, that would be able to at least point me in the right direction? Some of the problems I encounter I fix manually, and I'm sure there are a lot of best practices and best tools for the job I'm missing out of ignorance...

Thanks

# Answer
> 1 votes
to have a complete guide about CI/CD I think is not possible.. there is too much about processes, tools and customizations. Also the changes are fast and it should be updated every month.

The short answer is:
I have recently performed a complete CI/CD process in an enterprise environment using some of what you just told:

* devs pushing on gitlab (java, react) using gitflow plugin
* jenkins pipelines for every app automatically starts for dev environment doing unit tests, static code tests (sonarqube), integration tests (postman/soapui), updating artifacts on Nexus (mvn), and the pushing the deployment artifacts on the ArgoCD repo.
* ArgoCD manages then the K8S cluster resources

Long answer:
I use a few books as basic referrals, then I follow some youtube channel and I read specific articles to keep me updated.

I'll try to make here a starter list:

**Version Control**

**CI**

**CD**

**Ops**

**Youtube channels**

**Books**

I hope this can helps

# Answer
> 1 votes
Of course the information is endless, so I'll give you just one link to a series I found to be very good to combine the high level with the practice.

Note 2 things though:

* Reading a book usually gives you a more ordered understanding. Starting with one of the foundational is a good point. Like the ones mentioned here.
* There are several approaches around git to choose from: gitFlow, GitHub Flow, GitLab flow, Trunk based development. You need to "sew" the best for the specific team.

---
Tags: jenkins-pipeline, cicd, build-pipeline
---