# Question
Title: How to start start applications one after another with a shell script?
I'd like to automatically start all of the following applications after the system startup. However, they need to be started in a specific order and when the previous application is done booting.

The commands I'm now performing manually in the terminal are:

```
sudo docker-compose up
java -jar ./myapp.jar
python3 ./myapp.py
npm start ./myapp
chromium-browser www.my.app

```

So my java app needs to wait for the docker container to be started, otherwise it will fail to start. Analogically, the python app needs to wait for the java app to be started, and finally the web page needs to be opened after the angular frontend is ready to be served. Is there some easy way, how to handle this by a bash script, without getting way too deep with some DevOps tools? It's just a small pet project and I don't want to spend way too much time by over-engineering it.

# Answer
> 1 votes
Great, I was going to make a big disclaimer, but you have the right thing in mind, so I'll make a small one for people that come by and don't have the time to read it all thoroughly.

\** NOT FOR PRODUCTION \**

1. This will be a cycle of starting an app and waiting for a condition. In order for your script to progress from one command to the next, you will need to start all the applications in the background.

So, in a nutshell

```
~ start app & #don't wait for the script to end
~ some waiting script # runs until condition passes

```

Here's a good example of a waiting script: https://github.com/vishnubob/wait-for-it

In a nutshell what this wait-for-it script does, you can implement manually by creating a while loop that runs until a timeout or until some condition is valid.

Examples of valid conditions:

* status 200 on localhost on port 8000

You could implement these bash functions manually, it's basically a while loop and if and a counter, but I'll assume you don't want to waste time on it and I'll make an example script using the wait-for-it.sh

So, here it is:

```
#! /bin/bash

sudo docker-compose up -d # -d will start the containers in detached mode
./wait-for-it.sh localhost:12345 #replace 12345 with the correct port
java -jar ./myapp.jar & # &sign, sends the app to the background
./wait-for-it.sh localhost:12345
python3 ./myapp.py &
./wait-for-it.sh localhost:12345
npm start ./myapp &
./wait-for-it.sh localhost:12345
chromium-browser www.my.app

#this is kill all background processes when you quit this script
trap 'kill $(jobs -p)' EXIT

#this will wait for all the background processes to quit before letting this script exit
wait -n

```

# Answer
> 2 votes
If you're already launching one of these services with Docker Compose, I think it would be a very small lift to Dockerize the remaining Java, NodeJS, and Python components. When you have built a docker image for each one, then they can be configured to start in the correct order by using depends\_on in your compose file. Then you can bring them all up in the correct order by just running `docker-compose up`.

you can sleep for a bit before launching the browser, or monitor the stdout of the last service to start for a good "ready" message before launching chromium.

---
Tags: docker, spring-boot
---


# Question
Title: how to deploy same job on all my runners?
I have several VMs running `gilab-runner`, and I'm using `gitlab-ci` to deploy microservices into those VMs. Now I want to monitore those VMs with prometheus and grafana, but i need to setup `node-exporter/cadvisor` etc. service into those VMs.

My idea is using gitlab-ci to define a common job for those VMs.

I have already write the `docker-compose.yml` and `.gitlab-ci.yml`.

```
version: '3.8'

services:
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "9100:9100"

  cadvisor:
    image: google/cadvisor
    container_name: cadvisor
    restart: unless-stopped
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro
    ports:
      - "8080:8080"

```

```
deploy-workers:
  tags:
    - worker
  stage: deploy-workers
  script:
    - docker-compose -f docker-compose.worker.yaml pull
    - docker-compose -f docker-compose.worker.yaml down
    - docker-compose -f docker-compose.worker.yaml up -d

```

Then I register the runner in all my VMs with `worker` tag.

However, only one worker job is triggered during ci.

I have about `20` VMs to go.

Do anyone have suggestions?

# Answer
> 0 votes
GitLab is probably not the right tool for this. GitLab build pipelines are designed to produce output, not manage state on various servers. What system did you use to install and configure gitlab-runner on each of these servers? This is the sort of tool you're looking for to manage all of these servers.

---
Tags: gitlab-ci-runner
---


# Question
Title: How can we setup the services in my EC2 instance to startup automatically on boot?
When ever I restart my EC2 instance I have to manually use the command `systemctl start <service name >` to start the service.

Is there any option to automate this thing in the Linux platform?

# Answer
There are a lot of articles online regarding this, but here is one that should be simple enough =\> Link
> 1 votes

---
Tags: amazon-ec2, linux
---


# Question
Title: How to auto generate a diagram out of my AWS VPC?
Does AWS provide a tool to visualize my VPC?

I would like to generate an image file with all services (shown as icons) provisioned inside a VPC.

Tools like draw.io and others are available. But doesnt AWS provide a cloud native tool for this?

# Answer
> 7 votes
Yes and it costs 400$ a month.

https://docs.aws.amazon.com/solutions/latest/aws-perspective/welcome.html

It's a live diagram of all the resource in your organization, which means that it's capable of generating a live diagram for several accounts.

Seems crazy, but this can actually be useful to get a birdseye view of all the resources in complex scenarios. Also, nothing is keeping you from starting this service, letting it run for an hour, getting a screenshot and shutting it all down.

If that is not good enough, lucid chart and cloudcraft are two good alternatives from trustworthy companies. Be very careful when granting read access to your accounts.

https://www.lucidchart.com/pages/aws-architecture-import

https://www.cloudcraft.co/

---
Tags: amazon-web-services, images, aws-vpc, architecture
---


# Question
Title: View billing and cost management dashboard info with AWS CLI
The aws web console under "Billing" (https://console.aws.amazon.com/billing/) shows "Month-to-Date Spend by Service" which breaks down costs incurred so far this month by each service that is in use by an account.

It also shows the "Spend Summary" which shows the recent monthly total incurred cost as well as this month's forecast.

Is there a way to retrieve this information using the AWS CLI?

# Answer
> 1 votes
yes it is, I made a lambda function that posted it to a slack channel.

This is the CLI reference ce = cost-explorer

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ce/index.html

I remember there was a tricky part and if I'm not mistaken the forecast would be from today to the end of the month, so as the days passed it would decrease. When I built my version we were doing a lot of cost optimizations so it was very deceiving hahaha

So if you want the cost forecast to match the dashboard, you have to get the summary + the forecast. Not something super tricky, just something to watch for.

---
Tags: aws-cli, billing
---


title: helm install causes nil pointer

text:
# Question
Title: helm install causes nil pointer
I'm really a beginner with kubernetes and really struggle with this simple tutorial from baeldung.com

The only thing I did different (intentionally) was using a google cloud cluster instead of minikube.

Basically this is what I did so far:

1. Installed google cloud sdk.
2. Initialized gcloud with my google cloud cluster.
3. Installed helm.
4. Created helm charts like told in the tutorial.
5. Changed service.yaml, values.cyaml and deployment.yaml like told in the tutorial.

And when I now run

```
helm install hello-world .

```

I get this error message:

```
Error: template: hello-world/templates/serviceaccount.yaml:1:14: executing "hello-world/templates/serviceaccount.yaml" at <.Values.serviceAccount.create>: nil pointer evaluating interface {}.create

```

To be honest I'm not even sure the serviceaccount.yaml is here for and I'm grateful for any advise!

# Answer
You can try below options to debug this further.

First verify `values.yaml` and check the values for `serviceAccount` (default value is true ) that means the helm chart when deployed will create a service account for the deployment. When you create a pod, **if you do not specify a service account, it is automatically assigned the default service account in the given namespace**.

```
serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name:

```

Try to deploy your helm chart with create: false and verify if it solves your issue.

Else remove the file `hello-world/templates/serviceaccount.yaml` and mark serviceaccount as `create: false` in `value.yaml` and pass name as default service account of your deployment try to deploy as below

Note I have removed the `serviceaccount.yaml`

```
~/hello$ tree
.
└── hello-world
    ├── charts
    ├── Chart.yaml
    ├── templates
    │   ├── deployment.yaml
    │   ├── _helpers.tpl
    │   ├── ingress.yaml
    │   ├── NOTES.txt
    │   ├── service.yaml
    │   └── tests
    │       └── test-connection.yaml
    └── values.yaml

4 directories, 8 files

```

set create field as false under `values.yaml`

```
$ cat hello-world/values.yaml | grep -i serviceaccount -A 10

serviceAccount:
  # Specifies whether a service account should be created
  create: false
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: default

```

You can fetch your list of serviceaccounts available as below

```
$ kubectl get serviceaccounts
NAME      SECRETS   AGE
default   1         2d4h

```

Once deployed helm list will show the namespace used to deploy your chart and serviceaccount from the name space is used for deploeyemnt

```
$ helm list
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART               APP VERSION
hello-world-1580665905  default         1               2020-02-02 17:51:45.631330487 +0000 UTC deployed        hello-world-0.1.0   1.16.0

```

Get chart details and values post deploeyemtn as below

```
$ helm show chart hello-world
apiVersion: v2
appVersion: 1.16.0
description: A Helm chart for Kubernetes
name: hello-world
type: application
version: 0.1.0

$ helm show values hello-world | grep -i serviceaccount -A 10
serviceAccount:
  # Specifies whether a service account should be created
  create: false
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: default

podSecurityContext: {}
  # fsGroup: 2000

```

Get deployed resources as below

```
$ kubectl get all -o wide
NAME                                          READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
pod/hello-world-1580665905-84b9d4d469-xv5mx   1/1     Running   0          118s   192.168.58.215   k8s-node02   <none>           <none>

NAME                             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE    SELECTOR
service/hello-world-1580665905   ClusterIP   10.108.73.21   <none>        80/TCP    118s   app.kubernetes.io/instance=hello-world-1580665905,app.kubernetes.io/name=hello-world
service/kubernetes               ClusterIP   10.96.0.1      <none>        443/TCP   2d4h   <none>

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS    IMAGES         SELECTOR
deployment.apps/hello-world-1580665905   1/1     1            1           118s   hello-world   nginx:1.16.0   app.kubernetes.io/instance=hello-world-1580665905,app.kubernetes.io/name=hello-world

NAME                                                DESIRED   CURRENT   READY   AGE    CONTAINERS    IMAGES         SELECTOR
replicaset.apps/hello-world-1580665905-84b9d4d469   1         1         1       118s   hello-world   nginx:1.16.0   app.kubernetes.io/instance=hello-world-1580665905,app.kubernetes.io/name=hello-world,pod-template-hash=84b9d4d469

```
> 1 votes

# Answer
Be aware that there you can have also this message with some charts when using helm 3 \< 3.7.0

Reference: https://github.com/nextcloud/helm/issues/163
> 0 votes

---
Tags: kubernetes, helm
---


# Question
Title: Azure Kubernetes pod is inaccessible from another pod
Internally we have a Spark Executor and Spark Driver running in Kubernetes.

When you run a Spark Job in Kubernetes, Spark will create 2 types of pods Spark Drivers and Spark Executors. The Spark Executors communicate over TCP with Spark Driver using the internal DNS entry of each other's pod.

Suddenly today, the Spark Executor is unable to communicate with the Spark Driver. We get an DNS Unknown Host error meaning it is not able to resolve `pod-name`.`namespace`.

During troubleshooting, we notice that no pods in the cluster can communicate to this Pod via `pod-name`.`namespace`.

During troubleshooting, we created a Kubernetes `Service` entry to the pod. We can successfully communicate to the pod using the service DNS entry.

What is recourse for these sorts of issues to solve this sort of DNS lookup issues in Azure? We are opening a ticket with Microsoft for starters.

# Answer
> 0 votes
Restarting the CoreDNS services has fixed the issue. Apparently there is some stale state it can get into. So if you see this behavior, a restart kicks it back into the right state. This is quite rare so it should be OK.

---
Tags: kubernetes, azure, dns
---


# Question
Title: What is CI and how is it different from CT?
Wikipedia insists that

> (CI) is the practice of merging all developers' working copies to a shared mainline several times a day

which sounds to me like "branches are prohibited" which makes no sense. I am a huge proponent of the rebase workflow on master but would never insist it scales well - that's what feature branches are for.

Atlassian instead states

> \[CI\] allows software developers to work independently on features in parallel. When they are ready to merge these features into the end product, they can do so independently and rapidly.

This sounds to me like CT. Where's the "integration" part?

The question:

How is CI defined? Who emits the definition? How is it different from CT?

# Answer
Continuous Testing is an important part of a fast development process. You can detect bugs much faster and find them more easily since the code changes are smaller. But that's independent from integrating my feature into the product of the main/master branch. I could also test very often on my feature branch and never integrate it. So it is a requirement for Continuous Integration but it's not restricted to only that integration model.

The difference between the two definitions of Continuous Integration is not that big. Both state, that you should integrate your features rapidly or multiple times a day.

If you cut your features into smaller parts, you can also merge them more often into your main/master branch. You should write your code in a non breaking way, to be able to integrate often. The continuous testing helps a lot to ensure, that the changes don't break anything.

The important part of CI is, that you get immediate feedback on your code and that each developer is working with the same code base. So you don't have bigger problems with merging of huge feature branches at the end of the development. The problem with huge feature branches and late integration is the following: You finish your development and test everything on your feature branch. When you merge it into the main/master branch, the build breaks because there are some changes on main/master that are incompatible with yours. So you need to recode some parts, redo the tests and retry the merge. This could be prevented, if everyone would be using the latest codebase and all changes are integrated into that codebase continuously.

You can also use trunk based development (https://trunkbaseddevelopment.com/) as an extreme form of CI. All work is done on the main/master branch, that is called trunk in this model. Extensive automated tests ensure, that your commits don't break anything.

There is no organisation that has the ownership of the concept Continuous Integration, so everyone could publish his or her own definition of it.
> 0 votes

# Answer
We can use CT as a small part of the big box we call CI.

Nothing will change the fact that it's all part of an accepted general concept called CI and within that CI, you can wrap all the steps you need, as long as you don't forget that **the main goal is the automatic integration of all the new code to the codebase**.

You define and automate what is required for a new code to integrate the codebase. And if in your case that requires automated testing, then CT is part of your CI.

If your project only requires formatting standards, for example, then you have a CI process that doesn't have CT steps.

If the goal was just to test the code, then we would only test the new code. The rest of the code is already tested, right? So why bother?

We bother because we know that one line of code in the wrong place can implode a project, so we test the whole thing. We are not testing the new code, we are testing to ensure that the new code plays nice with the rest of the codebase.

So the main thing is not the testing, is the integration, the testing is just a tool we use to get there.
> 0 votes

# Answer
Well, here is a blog that might help you which provides short and clear answer about the use of CI, CT and also CD too. https://www.bunnyshell.com/blog/what-is-ci-cd-ct-devops
> 0 votes

---
Tags: continuous-integration
---


# Question
Title: Terraform: add to existing AWS policy, or create policy if needed
Several of our terraform root modules need add to an existing policy that provides read-only permissions for S3 buckets -- each module has its own bucket. I cannot figure out how to add to the existing policy, and merge new values (the new bucket) into it.

At first, we had just attached a new policy (three actually, one for development, staging, production) to the role. But we can only attach a maximum of 20 policies. So instead, I used the AWS CLI and just listed all the production buckets in one policy, staging, and dev likewise. Cool so far.

Now I want to accomplish the same thing with terraform.

I have created a submodule that the root modules can all call, passing their bucket in.

I can define the new policy as

```
data "aws_iam_policy_document" "read_only" {
  statement {
    actions = [
      "s3:ListBucket",
      "s3:GetObject",
      "s3:GetBucketLocation",
    ]
    effect = "Allow"
    resources = [
      "${var.bucket_arn}/*",
      var.bucket_arn,
    ]
  }
}

```

I can look up an *existing* policy with

```
data "aws_iam_policy" "existing" {
  name = "read-only-s3-${terraform.workspace}"
}

```

and potentially merge that with the new policy using

```
data "aws_iam_policy_document" "merged" {
  source_json = [
    data.aws_iam_policy_document.read_only.json,
    data.aws_iam_policy.existing.json
  ]
}

```

and then create the resource

```
resource "aws_iam_policy" "read_only_policy" {
  name        = "read-only-s3-${terraform.workspace}"
  path        = "/"

  policy = data.aws_iam_policy_document.merged.json
}

```

But this fails if there's no `data.aws_iam_policy.existing` because AWS cannot find it so terraform fails with an error.

There's a great deal of documentation about how to merge policies in the policy document reference, but there's very little indication of how to determine if there's an existing policy.

I could recreate the entire policy if I could find the existing one and merge it with the new one, or even if I just knew the names of the buckets in the existing policy. But the existing policies are created in other root modules. And there's no way to look up buckets other than by their name (no `tags` or `filter` on `data "aws_s3_bucket"`).

Is there a way to determine that there's an existing policy and get without throwing an error? Then I could get its policy document and use the `source_json` approach.

Is there a way that I can merge a new policy document onto whatever exists (or not)?

Open to other approaches. Really would prefer to keep this in IAM and not go to bucket policies because they are so opaque and decentralized.

# Answer
This is not a good way to go about this, terraform is a declarative language and you should always follow this principle.

Either terraform is managing a resource or terraform is querying an existing resource in order to provide information to manage a resource. If you allow scripting, very soon people will be implementing OOP, interaces, generics and it loses the whole focus.

With that out of the way, yes, you can do this. What you need is the policy document, in that case, you can use some non standard strategies like an external data source

the external data source will return a string with instructions for what to do next. If the policy exists, it returns "yes" if it doesn't it returns "nope"

```
data "external" "iam-policy-exists" {
  program = ["bash", "${path.module}/iam-policy-exists.sh"]

  query = {
    policy = "read-only-s3-${terraform.workspace}"
  }
}

```

then, the bash script that will check if the iam policy exists

iam-policy-exists.sh

```
#! /bin/bash

aws iam get-policy $1 #tries to fetch the policy

if $? == "0"; then #$? returns the result of the last command, 0 is success
    echo '{"exists":"yes"}'
else
    echo '{"exists":"nope"}'
fi

```

then you have a data query with a count

```
data "aws_iam_policy" "existing" {
  #this count == 1 if the policy exists
  count = data.external.iam-policy-exists.exists == "yes" ? 1 : 0
  name = "read-only-s3-${terraform.workspace}"
}

resource "aws_iam_policy" "read_only_policy" {
  #this will be 1 if the policy doesn't exists
  count = data.external.iam-policy-exists.exists == "nope" ? 1 : 0
  name        = "read-only-s3-${terraform.workspace}"
  path        = "/"

  policy = data.aws_iam_policy_document.merged.json
}

```

So far, this is what you wanted, to either query or create an IAM policy.

Now, if you want to create a second merged policy you can get the resulting json

```
locals {
    iam_policy_json = data.external.iam-policy-exists.exists == "yes" ? data.aws_iam_policy.existing[0].json : resource.aws_iam_policy.read_only_policy[0].json
}

```

and now, you have the json policy on local.iam\_policy\_json

Disclaimer, see how ugly things get when you try to do the procedural way? I'm not trying to compel you to do this differently, but it would be a good idea to rethink your approach to this.
> 3 votes

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


# Question
Title: CentOS Docker Container running Libero SoC: Unable to to connect to X Server
I am running Libero SoC on a CentOS Docker Container (CentOS Linux release 7.9.2009 (Core)). This container will be used to build FPGA code within a CI/CD pipeline. When I attempt to execute a script (that simply prints `"Hello, world"`) with the command `libero SCRIPT:printhelloworld.tcl`

I receive the following error:

```
libero_bin: cannot connect to X server

```

I would not have expected libero to require an X server just to run a .tcl script.

Thank you.

# Answer
> 2 votes
Suggest looking at this example of libero docker image that uses Ubuntu: https://github.com/AngelTerrones/ubuntu-libero

---
Tags: docker
---


title: Prodding Helm to refresh a deployment?

text:
# Question
Title: Prodding Helm to refresh a deployment?
I am using Flux to automatically deploy a Helm Release from a git repository to a Kubernetes cluster. If I directly edit a resulting *deployment* object's spec (using `k9s` or `kubectl edit`, e.g. to temporarily try a different version of container image) then Kubernetes will roll out the new pods with no downtime. How can I revert such changes, that is, how can I trigger updating of the *deployment* (and other objects) to match the *hr*, without interrupting service?

If I manually delete the *hr* then the service will briefly go down before I can re-run the Flux pipeline to recreate it. If I materially changed the git repo, then the modifications would auto-deploy without downtime, but re-running the pipeline with inconsequential commits appears not to refresh the *deployment*.

# Answer
> 1 votes
Say you have a CI pipeline that, upon any git push/merge, logs into a kubernetes cluster and runs the command `fluxctl sync` (and then uses `kubectl rollout status` on each deployment object, to wait for completion before following up with tests). The flux daemon/agent itself may also check and perform syncs periodically (as well as checking container registries for new image tags to commit to the manifests in the repo).

Presuming that the git repo consists of helm releases, then flux should ensure that the hr's in the cluster are kept consistent with those in the repo. But flux shouldn't affect any cluster objects that are *not* directly represented in the repo. Instead, *Helm* is responsible for ensuring the cluster has deployments matching the hr's. (And then, the deployment controller is responsible for ensuring pods exist matching the deploy spec.)

The flux sync apparently does nothing if the git head commit hasn't changed (or even if the changes in the repo do not appear significant?). If you are unwilling to engineer a new commit, an option with only brief downtime would be: `kubectl delete hr foo` then `fluxctl sync`.

Presuming that only the deployment (rather than the hr) has been mutated, another possibility may be to issue `helm rollback foo <latest-revision>` (although this isn't guaranteed to succeed cleanly).

*If* the deployment has only been edited *once*, then `kubectl rollout undo deploy foo` is appropriate.

# Answer
> 0 votes
Flux is pretty smart and has some built it mechanism to avoid unnecessary updates.

Helm has a version in the Chart.yaml, I'm assuming an inconsequential commit wouldn't update this version so flux might be assuming that it doesn't need to do anything. Changing the version would be something to try.

To avoid the downtime problems, you need to double check your configs. Are you using the replace strategy to the install? Are you using force updates? Both of those strategies would delete the deployments before updating and that might be the cause of your downtime.

---
Tags: kubernetes, helm
---


# Question
Title: Git keeps asking for ssh passphrase when SSH is already defined in GitLab
I'm playing around with a personal GitLab account to get familiar with its' ins and outs. First, I followed this primer on setting ssh keys and added public and private ED25519 keys to `~\.ssh`. I added the public key to my GitLab account. Then, using the `glab` CLI I was able to set up a repository which I could push to and pull from using `git`.

Unfortunately, `git` still prompts me for my SSH passphrase every time I try to push to the repo. I tried the following:

The known host entries didn't have any noticeable effect on this behavior. Verifying I could connect threw the following error:

> ssh: Could not resolve hostname https://gitlab.com/my\_username

Why is `git` asking me to provide my passphrase every time I push and how can I fix this once and for all?

# Answer
> 5 votes
You can try adding your passphrase to the keychain using `ssh-add -K`, this will ask you the passphrase for the first time and later on it won't ask.

# Answer
> 1 votes
Passphrase is defined by the way you created your private key. When creating a key pair you need to opt for no passphrase on the private key - this should solve your issue.

---
Tags: gitlab, git, ssh
---


# Question
Title: How to migrate away from `docker-machine create`?
I have an old script that uses `docker-machine create` to create an number of Hyper-V VMs and run a server application inside each one, using docker. It was done this way because the application instances use hard-coded port numbers, and would run into port-collisions if all the application would try to bind to the same port. Creating a machine for each one prevents this collision because each machine has it's own IP. All the VMs are running on the same physical hardware.

`docker-machine` has been deprecated a while now, so what's the modern way to achieve the same?

What I'm looking for is to be able to run multiple instances of the server application on the same physical hardware, while also having all the applications listening to the same host port. While I realise that I would ideally remove the need for fixed port numbers, this is a bigger job than I can undertake right now because the port number is also hard-coded in deployed client applications.

# Answer
Anything that hasicorp created.

* Vagrant
* Terraform
* Ansible

All tools for automating deployment of VM's and packages running on top of the VM's. API-based and all major providers implement the API's, also for on premise there implementations from VMWare, Virtualbox etc.

Like you said there's many new terms to learn before you can work with it but it's a good path to follow
> -1 votes

---
Tags: docker, networking, docker-machine
---


title: How to get kubernetes pod network CIDR

text:
# Question
Title: How to get kubernetes pod network CIDR
I have a running k8s cluster initialized with `kubeadm`.

On initialization, I did not pass the option `--pod-network-cidr`

How do I get the CIDR of the pod network

I tried

* Looking at the `/etc/kubernetes/manifests/kube-apiserver.yaml` which seems to be the manifest for kube-apiserver used by `kubeadm` but that information is not included
* Looking at the `kubeadm` document but I couldn't find a default value

# Answer
> 27 votes
This command will give you the pod CIDR addresses for each of the nodes in your cluster.

`kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'`

# Answer
> 13 votes
This will show pod network CIDR which used by `kube-proxy`

```
kubectl cluster-info dump | grep -m 1 cluster-cidr

```

# Answer
> 9 votes
my version of `kubeadm` is 1.22 and the command to view defaults is `kubeadm config print init-defaults`, towards the bottom:

```
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12

```

# Answer
> 4 votes
The `--cluster-cidr` / `--pod-network-cidr` is fed to `kube-controller-manager` config.

You can simply do `ps -ef | grep "cluster-cidr"` to get what you want.

# Answer
> 2 votes
It's in file `/etc/kubernetes/manifests/kube-controller-manager.yaml`

```
# sudo grep cidr /etc/kubernetes/manifests/kube-*
/etc/kubernetes/manifests/kube-controller-manager.yaml:    - --allocate-node-cidrs=true
/etc/kubernetes/manifests/kube-controller-manager.yaml:    - --cluster-cidr=192.168.0.0/16
/etc/kubernetes/manifests/kube-controller-manager.yaml:    - --node-cidr-mask-size=24

```

# Answer
> 1 votes
With kubeadm

`kubeadm config view | grep Subnet`

# Answer
> 1 votes
There are a few options (combining the existing answers and adding option for Calico, including example ouput):

**Option 1**: Run this command On the master node (also applicable when running for example microk8s on Ubuntu)

* **kubeadm config view | grep Subnet**

example output from local 3 node cluster, master node

```
podSubnet: 172.16.0.0/16
serviceSubnet: 10.96.0.0/12

```

**Option 2**: Run this command on the master node:

* **ps -ef | grep cluster-cidr**

example output from local machine running microk8s

```
vincent   6841 27089  0 09:52 pts/7    00:00:00 grep --color=auto cluster-cidr
root      7053     1  0 feb12 ?        00:00:14 /snap/microk8s/1173/kube-proxy --kubeconfig=/var/snap/microk8s/1173/credentials/proxy.config --cluster-cidr=10.152.183.0/24 --healthz-bind-address=127.0.0.1

```

**Option 3**: Run this command on the master node:

* **sudo grep cidr /etc/kubernetes/manifests/kube-\***

Example output of same master node:

```
/etc/kubernetes/manifests/kube-controller-manager.yaml:    - --allocate-node-cidrs=true
/etc/kubernetes/manifests/kube-controller-manager.yaml:    - --cluster-cidr=172.16.0.0/16
/etc/kubernetes/manifests/kube-controller-manager.yaml:    - --node-cidr-mask-size=24

```

If you run Calico you have the option to use calicoctl:

https://docs.projectcalico.org/v3.5/usage/calicoctl/install

This documentation shows how to show and also change the cidr: https://docs.projectcalico.org/v3.2/usage/changing-ip-pools

**Option 4** (Calico): Run this command to view the cidr:

* **CALICO\_KUBECONFIG=~/.kube/config DATASTORE\_TYPE=kubernetes calicoctl get ippool -o wide**

Example output for the same cluster (works from any place that has the proper kubectl config and connection to the cluster):

```
NAME                  CIDR            NAT    IPIPMODE   DISABLED   SELECTOR
default-ipv4-ippool   172.16.0.0/16   true   Always     false      all()

```

Depending on your network option, you may have other options which are hopefully documented in the respective documentation.

# Answer
> 1 votes
To get Service IP range - i.e. IP's assigned to ClusterIP, the command is:

* `ps -aux | grep kube-apiserver | grep service-cluster-ip-range` (you can run this on master node)
* `cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep service-cluster-ip-range`

To find the Pod network range, when you have defined your cluster using kubeadm 1.22 and used weave as your networking addon: first find the weave pod name using

`kubectl get pod -n kube-system | grep weave`

Copy any one name out of the three pod names.

```
kubectl -n kube-system logs <<weave-net-podname-from-above-step>> -c weave | grep ipalloc-range

```

you will find either default i.e. 10.32.0.0/12 or whatever range you assigned during kubeadm init

---
Tags: kubernetes, networking
---


# Question
Title: Monitoring Kubernetes CronJob & Job in Grafana for today day only
I'm trying to create a Dashboard in Grafana that will show the status of Cronjob & Job success & fail.

Currently i'm using `kube_job_status_succeeded` to get a status job, but the issue here PromQL also take a 3 days of job status back, but i only wanted for 1 days job status.

I try to be creative with `kube_job_created` but no luck.

How can i get only `kube_job_status_succeeded` for 1 day only ? Thank you.

# Answer
> 1 votes
I had similar problem. I found no straightforward solution, bur eventually I solved it with a workaround.

The problem is that `kube_job_status_succeeded` will always present number of rows equal to `.spec.successfulJobsHistoryLimit` (if some jobs in the past have succeded) with value of 1, and number of rows equal to `.spec.failedJobsHistoryLimit` (if some jobs in the past have failed) with value of 0. Moreover, `kube_job_status_succeeded` does not tell you when the job was performed.

In other words, `kube_job_status_succeeded` just store `.spec.successfulJobsHistoryLimit` (default: 3) of most recent succesful jobs and `.spec.failedJobsHistoryLimit` (default: 1) of most recent failed jobs

My workaround is based on joining data from kube\_job\_status\_succeeded and kube\_job\_created. In this way, I take most recent timestamp of successful job. Then I deduct it from current timestamp. In result I get a info how long ago last successful job execution took a place.

```
time() - max(kube_job_status_succeeded{namespace="my_namespace",job_name=~"job_name.*"} * on (job_name) kube_job_created{namespace="my_namespace",job_name=~"job_name.*"})

```

In Grafana it looks like this:

Maybe this is not direct answer to your question, but I believe that this might be a good starting point to achieve your goal. In Grafana you can do some data mapping to present time diff calculated in the query as one big "success"/"failed" label, depending on your neads

# Answer
> 0 votes
Did you try to set the `.spec.successfulJobsHistoryLimit` to 1 instead of the default value of 3?

https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#jobs-history-limits

---
Tags: kubernetes, monitoring, prometheus, grafana
---


# Question
Title: Terraform/AWS Macie: how to use managed data identifiers?
I am trying to enable AWS Macie via Terraform to run scheduled jobs that scan S3 buckets for sensitive data.

I've been able to create an account and execute an initial scan of my buckets, but I would also like to specify a few managed data identifiers (*e.g., address, DOB, drivers license, phone number, etc*).

Looking at the HashiCorp documentation (https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/macie2\_classification\_job), I only see information about custom data identifiers.

The AWS REST API docs suggests there is a way using the `managedDataIdentifierIds` property in `CreateClassificationJobRequest` but I am struggling to apply it within Terraform.

Defining custom data identifiers may be a workaround, but would I'd like to avoid this path if possible.

**How do I use managed data identifiers via Terraform?**

```
resource "aws_macie2_account" "test_scan" {}

resource "aws_macie2_classification_job" "test_scan" {
    job_type = "ONE_TIME"
    name     = "init_test_scan"
    s3_job_definition {
        bucket_definitions {
            account_id = var.account_id
            buckets    = var.buckets
        }
    }

    sampling_percentage = 100

  depends_on = [aws_macie2_account.test_scan]
}

```

# Answer
> 1 votes
It seems that there is no official support for it yet. This is a brand new feature released on Sep 23rd, 2021, see below:

https://aws.amazon.com/about-aws/whats-new/2021/09/amazon-macie-managed-data-identifiers/

I have created a feature request to the community, your support will be very appreciated:

https://github.com/hashicorp/terraform-provider-aws/issues/21952

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


# Question
Title: network_security_group_id not expected in azurerm_network_interface
I'm following a lecture on terraform for azure. They add a property network\_security\_group\_id to an azurerm\_network\_interface

```
resource "azurerm_network_interface" "demo-instance" {
    name                        = "${var.prefix}-instance1"
    location                    = var.location
    resource_group_name         = azurerm_resource_group.demo.name
    network_security_group_id   = azurerm_network_security_group.allow-ssh.id

    ip_configuration {
      .....
    }
}

```

But 'terraform plan' spits out

> Error: Unsupported argument │ │ on instance.tf line 43, in resource "azurerm\_network\_interface" "demo-instance": │ 43:
> network\_security\_group\_id = azurerm\_network\_security\_group.allow-ssh.id │ │ An argument named "network\_security\_group\_id" is not expected here.

I'm guessing that this has moved somewhere else in some version, but I can't find the setting in the docs anywhere.

Where does network\_security\_group\_id belong?

```
resource "azurerm_network_security_group" "allow-ssh" {
    name                    = "${var.prefix}-allow-ssh"
    location                = var.location
    resource_group_name     = azurerm_resource_group.demo.name

    security_rule {
        name                    = "SSH"
        priority                = 1001
        direction               = "Inbound"
        access                  = "Allow"
        protocol                = "Tcp"
        source_port_range       = "*"
        destination_port_range  = var.ssh-source-address
        destination_address_prefix  = "*"
    }
}

```

Just removing these resources and settings and it works anyway. The resources get created and I'm able to login with a key. So is this not needed anymore at all?

# Answer
Found the answer, this has changed at some point.

What's needed is a network\_security\_group\_association which relates to a subnet\_id and a network\_security\_group\_id (the one that was in the network\_security\_group before)

```
resource "azurerm_subnet" "subnet-internal-1" {
  name                 = "${var.prefix}-internal-1"
  resource_group_name  = azurerm_resource_group.geofriends.name
  virtual_network_name = azurerm_virtual_network.vn.name
  address_prefixes     = ["10.0.0.0/24"]
}

resource "azurerm_network_security_group" "allow-ssh" {
   name                    = "${var.prefix}-allow-ssh"
   location                = var.location
   resource_group_name     = azurerm_resource_group.geofriends.name

   security_rule {
       name                    = "SSH"
       priority                = 1001
       direction               = "Inbound"
       access                  = "Allow"
       protocol                = "Tcp"
       source_port_range       = var.ssh-source-address
       destination_port_range       = var.ssh-destination-address
       source_address_prefix        = var.ssh-source-address
       destination_address_prefix   = var.ssh-destination-address
   }
}

resource "azurerm_subnet_network_security_group_association" "sec-group-association" {
  subnet_id                 = azurerm_subnet.subnet-internal-1.id
  network_security_group_id = azurerm_network_security_group.allow-ssh.id
}

```

Now the subnet subnet-internal-1 contains the allow ssh security\_group
> 0 votes

---
Tags: terraform, azure-devops, azure
---


# Question
Title: How to close a branch by default after a pull request has been merged in Bitbucket?
By default a branch will remain in Bitbucket when a Pull Request (PR) has been merged. How to ensure that a branch will be removed after a PR has been removed?

When the option is enabled then the branch will be removed after the merge of a PR, but how to ensure that it is clicked by default to prevent that creators of the PR forget to click it and the branch remains in bitbucket?

# Answer
> 4 votes
Apparently selecting the `Close branch` option in the very dialogue illustrated in your question will actually delete the branch as well. From Why only "Close" a branch instead of "Delete" it?:

> Ben Tatham Jun 15, 2014
>
> It seems that I was mistaken. Marking a pull request to *Close branch when merged*, does indeed Delete it. I'm not sure why they use different language for that though.

# Answer
> 6 votes
What I really want is to add a comment to the accepted answer, but I don't have enough reputation to do so. So I'll note it here. I've closed BSERV-10344 because it's in the wrong tracker. This question is about Bitbucket Cloud (bitbucket.org), not Bitbucket Server (the behind-the-firewall version). The correct issue tracker for the feature request is at https://bitbucket.org/site/master/issues.

Also, re: "I'm not sure why they use different language for that", it's because Bitbucket Cloud supports Mercurial as well as Git. In Mercurial it's not possible to delete a named branch; they can only be closed. Since its support for Mercurial predates its support for Git, the terminology used is to "close" the branch.

# Answer
> 4 votes
For Bitbucket Server you can set this up on a project or repo-level under Settings \> Branches (under the Workflow section), scroll to the bottom and tick this setting on and press save:

So all in all you have two options:

1. Change this setting on a project-level and have all repos under it inherit the project's settings by default
2. Change this setting on a repo-level (if you want only some of your repos to adhere to this)

---
Tags: bitbucket
---


# Question
Title: Apache Camel-k metrics in rancher embedded prometheus
I have a Kubernetes running Rancher 2.4.3. I have the cluster monitoring enabled in rancher, so that exists a Prometheus instance running, so as a Prometheus Operator.

Recently I deployed a Apache Camel-K operator, and now I want to enable the prometheus integration for collect metrics about my camel routes.

So, my Camel-K operator is running in namescape `camel-k` and the rancher embedded prometheus stack in `cattle-prometheus` namespace.

I just have launched my route with the trait `--trait prometheus.enabled=true`, but the camel metrics aren't listing at my prometheus.

Anyone knows why or what I need to configure to my camel-k route deploy it's metrics at the rancher embedded prometheus?

# Answer
> 0 votes
Solved updating the prometheus operator 0.38.1 -\> 0.39.0.

More details: https://github.com/apache/camel-k/issues/2794

---
Tags: kubernetes, prometheus, rancher
---


# Question
Title: Trying to run a simple API GET request for private Gitlab account
I am trying to run a simple API request to GitLab through powershell 5.1. After generating an access token with all privileges using the Web UI I tried to run the following:

`invoke-restmethod https://gitlab.com/api/v4/projects?private_token=<my_private_token>/<project_id>`

Unfortunately, I get an error:

```
invoke-restmethod : {"message":"401 Unauthorized"}
At line:1 char:13
+ $response = invoke-restmethod https://gitlab.com/api/v4/projects?priv
...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebReques
   t:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.Pow
   erShell.Commands.InvokeRestMethodCommand

```

Why am I getting 401 error when I try to access project related information?

# Answer
> 1 votes
The parameter should come at the end of the URL:

```
Invoke-RestMethod -Uri https://gitlab.com/api/v4/projects/1234567?private_token=$my_private_token

```

I prefer to pass the token in the header:

```
Invoke-RestMethod -Headers @{ 'PRIVATE-TOKEN'=$_my_private_token } -Uri http://gitlab.com/api/v4/projects/1234567

```

https://docs.gitlab.com/ee/api/#personalproject-access-tokens

---
Tags: gitlab, api, powershell
---


# Question
Title: How to modify/allow firewall rules of a GCP instance directly from the CLI?
Is there anyway to allow the ports from CLI?
I have an instance in GCP and I have installed a service which by default runs on `Port:8080`. I know there is an option to change the firewall rules to allow ports from the GCP dashboard but **I'm wondering if there is any way to allow the required ports from the CLI**
In my case I'm using `Git Bash` rather than the native `GCP Cloud Console`
I have seen the documentation to allow ports from command line GCP Firewall-rules-from CLI but this is throwing a `ERROR` since I'm using the `Git Bash`.
Here is the error log:

```
[mygcp@foo~]$ gcloud compute firewall-rules create FooService --allow=tcp:8080 --description="Allow incoming traffic on TCP port 8080" --direction=INGRESS
Creating firewall...failed.
ERROR: (gcloud.compute.firewall-rules.create) Could not fetch resource:
 - Request had insufficient authentication scopes.

[mygcp@foo~]$ gcloud compute firewall-rules list
ERROR: (gcloud.compute.firewall-rules.list) Some requests did not succeed:
 - Request had insufficient authentication scopes.

```

Is there any option to allow required ports directly from the Git Bash CLI?

# Answer
Most probably, you are using the wrong account.

Find out which one you are currently using in CLI:

```
gcloud config configurations list
gcloud auth list

```

If the selected configuration is wrong, fix it and then retry with `gcloud compute firewall-rules create`.
> 2 votes

---
Tags: google-cloud-platform, bash, ports, firewall
---


# Question
Title: How to loop through json without an array
I am trying to work out how to iterate over some JSON that has repeated structures but have not used a list.

I am using the `ansible.posix.firewalld_info` module and it returns a dictionary for each zone:

```
{
"active_zones": true,
    "changed": false,
    "collected_zones": [
        "public",
        "work"
    ],
    "firewalld_info": {
        "default_zone": "public",
        "version": "0.9.3",
        "zones": {
            "public": {
                "forward": false,
                "forward_ports": [],
                "icmp_block_inversion": false,
                "icmp_blocks": [],
                "interfaces": [
                    "ens22",
                    "ens20",
                    "ens19",
                    "ens18"
                ],
                "masquerade": true,
                "ports": [
                    [
                        "9090",
                        "tcp"
                    ]
                ],
                "protocols": [],
                "rich_rules": [],
                "services": [
                    "ssh",
                    "cockpit",
                    "MyCustomService"
                ],
                "source_ports": [],
                "sources": [],
                "target": "DROP"
            },
            "work": {
                "forward": false,
                "forward_ports": [],
                "icmp_block_inversion": false,
                "icmp_blocks": [],
                "interfaces": [
                    "ens21"
                ],
                "masquerade": false,
                "ports": [],
                "protocols": [],
                "rich_rules": [],
                "services": [
                    "ssh",
                    "dhcpv6-client",
                    "cockpit"
                ],
                "source_ports": [],
                "sources": [],
                "target": "default"
            }
        }
    },
    "invocation": {
        "module_args": {
            "active_zones": true,
            "zones": null
        }
    },
    "undefined_zones": []
}

```

`public` and `work` are dictionaries. How can I iterate over each zone under `firewalld_info` in this JSON?

# Answer
Q: *"**How can I iterate over each zone?**"*

A: Convert the dictionary to a list, .e.g. given the data in the variable *result*

```
    - debug:
        var: item
      loop: "{{ result.firewalld_info.zones.public|dict2items }}"

```

gives (abridged)

```
  item:
    key: forward
    value: false

  item:
    key: forward_ports
    value: []

  item:
    key: icmp_block_inversion
    value: false

  ...

```

See with\_dict
> 4 votes

# Answer
Since Vladimir answered this in the ansible context I'm going to give you a way to process this in the shell.

As a one liner:

```
for zone in public work; do echo "another iteration"; cat fw.json | jq ".firewalld_info.zones.$zone"; done

```

Or as prettier code:

```
for zone in public work
do
        echo "another iteration"
        cat fw.json | jq ".firewalld_info.zones.$zone"
        # save it in a variable or pass it through another round of jq to extract details into variables
done

```

You're using `jq` to extract the subsections you want. The biggest limitation of these examples is that the zones are hard-coded. You can pull the keys out with jq to make this more flexible.
> 1 votes

---
Tags: ansible
---


# Question
Title: Lightweight alternative to healthchecks for flow-control in docker-compose
Currently I have a docker-compose.yaml which still contains `depends_on` with a `condition`. Unfortunately this feature got removed in newer versions. There is already a discussion here where some alternatives like healthcheck and dockerize are mentioned. But I specifically liked about `depends_on` that you don't have to do this. Also helathchecks get executed periodically, and dockerize seems to only work by wating for ports to be availabkle. It was so easy to configure the flow of your containers in a way that one starts after another.

So I was wondering if there is some alternative that is as easy as adding depends\_on into your compose-file. Without having to setup anything else? Maybe there is some way to utilize `docker events`?

# Answer
If your application is going mad about the database being not available, you can insert a "wait-for-port" call at the beginning of the entrypoint. This only makes sense if you stick to docker-compose. But a better solution will be using Kubernetes.

There are many implementations of wait-for programs around, but here is the Bitnami's Go binary: https://github.com/bitnami/wait-for-port

If you need run a sequence of jobs, here is the same question with good answers: https://stackoverflow.com/questions/40713573/how-to-run-containers-sequentially-as-a-kubernetes-job
> 0 votes

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


# Question
Title: AWS ECS Green/Blue with CodePipeline: The ELB could not be updated due to the following error: Primary taskset target group must be behind listener
I've been trying for hours to get a basic CodePipeline up and running with ECS Green/Blue. We're creating a prototype, so everything is in a single repo for now, and the `Dockerfile`, `taskdef.json`, `appspec.yaml` are all in a subfolder. I'm getting the following error:

`The ELB could not be updated due to the following error: Primary taskset target group must be behind listener arn:aws:elasticloadbalancing:eu-west-1:123:listener/app/api-lb/123/123`

It's a standard pipeline:

1. CodeCommit
2. CodeBuild
3. CodeDeploy to ECS

Commit and Build work and I'm passing the artifacts to the last step. Deployment fails though, with the error mentioned above.

I have no idea what exactly the "primary taskset target group" is. Both target groups *are* behind a listener.

I know there are Terraform modules for this, but I wanted to modify/extend this after it works, so I decided to start from scratch. Went through a dozen different articles, but I can't figure out what's wrong with my ECS config.

I created a repo with all the files here, here are the relevant the lb, ecs and CodeDeploy configs:

*lb*:

```
resource "aws_lb" "lb" {
  name               = "${var.name}-lb"
  internal           = false
  load_balancer_type = "application"
  subnets            = [aws_default_subnet.default_az1.id, aws_default_subnet.default_az2.id]
  security_groups    = [aws_security_group.blue_green.id]
}

resource "aws_lb_target_group" "blue" {
  name        = "${var.name}-blue"
  port        = 80
  target_type = "ip"
  protocol    = "HTTP"
  vpc_id      = aws_default_vpc.default.id
  depends_on = [
    aws_lb.lb
  ]
  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = "10"
    timeout             = "5"
    unhealthy_threshold = "3"
    healthy_threshold   = "3"
  }
  tags = {
    Name = var.name
  }
}

resource "aws_lb_target_group" "green" {
  name        = "${var.name}-green"
  port        = 80
  target_type = "ip"
  protocol    = "HTTP"
  vpc_id      = aws_default_vpc.default.id
  depends_on = [
    aws_lb.lb
  ]
  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = "10"
    timeout             = "5"
    unhealthy_threshold = "3"
    healthy_threshold   = "3"
  }
  tags = {
    Name = var.name
  }
}

resource "aws_lb_listener" "green" {
  load_balancer_arn = aws_lb.lb.arn
  port              = "80"
  protocol          = "HTTP"
  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.green.arn
  }
  depends_on = [aws_lb_target_group.green]
}

resource "aws_lb_listener" "blue" {
  load_balancer_arn = aws_lb.lb.arn
  port              = "8080"
  protocol          = "HTTP"
  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.blue.arn
  }
  depends_on = [aws_lb_target_group.blue]
}

```

*codedeploy*

```
resource "aws_codedeploy_app" "app" {
  compute_platform = "ECS"
  name             = var.name
}

resource "aws_codedeploy_deployment_group" "group" {
  app_name               = var.name
  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
  deployment_group_name  = "${var.name}-group-1"
  service_role_arn       = aws_iam_role.codedeploy-service.arn

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE"]
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
    }

    terminate_blue_instances_on_deployment_success {
      action = "TERMINATE"
    }
  }

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  ecs_service {
    cluster_name = aws_ecs_cluster.cluster.name
    service_name = aws_ecs_service.api.name
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [aws_lb_listener.green.arn]
      }

      test_traffic_route {
        listener_arns = [aws_lb_listener.blue.arn]
      }

      target_group {
        name = aws_lb_target_group.blue.name
      }

      target_group {
        name = aws_lb_target_group.green.name
      }
    }
  }
}

```

*ecs*:

```
resource "aws_ecs_cluster" "cluster" {
  name = var.name

  configuration {
    execute_command_configuration {
      kms_key_id = aws_kms_key.keys.arn
      logging    = "OVERRIDE"

      log_configuration {
        cloud_watch_encryption_enabled = true
        cloud_watch_log_group_name     = aws_cloudwatch_log_group.logs.name
      }
    }
  }
}

resource "aws_ecs_task_definition" "api" {
  family                   = "api"
  memory                   = 512
  cpu                      = 256
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  execution_role_arn       = aws_iam_role.ecs-task-service.arn

  container_definitions = jsonencode([
    {
      name      = var.name,
      image     = "${aws_ecr_repository.repo.repository_url}:latest"
      essential = true
      portMappings = [
        {
          "containerPort" = 8080,
          "hostPort"      = 8080
        }
      ],
      environment = [],
      log_options = {
        awslogs-region        = var.region
        awslogs-group         = var.name
        awslogs-stream-prefix = "ecs-service"
      }
    }
  ])
}

resource "aws_ecs_service" "api" {
  name            = var.name
  cluster         = aws_ecs_cluster.cluster.id
  task_definition = aws_ecs_task_definition.api.arn
  launch_type     = "FARGATE"
  desired_count   = 1
  depends_on      = [aws_lb_listener.green, aws_lb_listener.blue, aws_iam_role_policy.ecs-service-base-policy]

  deployment_controller {
    type = "CODE_DEPLOY"
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.blue.arn
    container_name   = var.name
    container_port   = 8080
  }

  network_configuration {
    subnets = [aws_default_subnet.default_az1.id, aws_default_subnet.default_az2.id, aws_default_subnet.default_az3.id]
    security_groups = [
      aws_security_group.ecs.id
    ]
    assign_public_ip = false
  }

  lifecycle {
    ignore_changes = [
      load_balancer,
      desired_count,
      task_definition
    ]
  }
}

```

Any hints on what I'm doing wrong? Thanks!

# Answer
> 2 votes
The underlaying issue was an IAM permission error. After clicking through the stack, the "tasks" in the cluster didn't start because of missing permissions/roles.

---
Tags: amazon-web-services, terraform, amazon-ecs, aws-codepipeline
---


# Question
Title: How can I determine an Ansible client's IP address in an OS-independent manner?
I have an Ansible environment in which machines are listed by hostname in the inventories. Occasionally, it is necessary to determine the IP address of a target machine in a playbook (note: in this context, I am only interested in the address of the interface that the Ansible control machine uses to connect to the client machine).

It seems that this is not easy to do in an OS-independent way: Linux clients define the dictionary `default_ipv4` in their `hostvars`, but Windows machines define the array `ip_addresses`.

This is how the relevant section of a `hostvars` dump from a Linux client looks:

```
ok: [sampleboxlin] => {
"hostvars[inventory_hostname].ansible_facts": {
    "all_ipv4_addresses": [
        "123.234.99.99"
    ],

```

and this is how things look on a Windows client:

```
ok: [sampleboxwin] => {
"hostvars[inventory_hostname]": {
  // shortened
  "hostname": "sampleboxwin",
        "interfaces": [
            {
                "connection_name": "Ethernet0",
                "default_gateway": "123.234.99.1",
                "dns_domain": null,
                "interface_index": 13,
                "interface_name": "Intel(R) 82574L Gigabit Network Connection",
                "macaddress": "0b:fu:sc:at:ed:00"
            }
        ],
        "ip_addresses": [
            "123.234.99.9"
        ],

```

So, what is the best-practice way of mapping hostnames to the host's IP address \[1\] in a playbook, in a robust and OS-independent way?

---

\[1\] again, we always assume that the client only has one relevant IP address, and we are interested in the one used to communicate with the Ansible controller

# Answer
Q: *"**IP address Ansible control machine uses to connect to the client machine.**"*

A: Find out to which IP the client resolves, e.g. running at the controller

```
    - debug:
        msg: "{{ lookup('community.general.dig', 'test_21') }}"

```

gives

```
ok: [localhost] =>
  msg: 10.1.0.71

```

If the play is running at the client delegate to localhost, e.g.

```
    - debug:
        msg: "{{ lookup('community.general.dig', inventory_hostname) }}"
      delegate_to: localhost

```

gives

```
ok: [test_21 -> localhost] =>
  msg: 10.1.0.71

```
> 5 votes

---
Tags: ansible
---


# Question
Title: How deploy public key to newly created VM on GCP?
I create VM instance using ansible module `gcp_compute_instance` My code:

```
---
- name: Create jenkins node-1
  hosts: localhost
  connection: local
  gather_facts: no
  vars:
    address: <my ip>
    project_id: geocitizen-app
    machine_type: f1-micro
    machine_name: jenkins-node-1
    image: https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-7-v20191014
    zone: europe-north1-a
    service_email: log@project-app.iam.gserviceaccount.com
    startup_script_url: gs://project/startup.sh
    service_account_scope: https://www.googleapis.com/auth/devstorage.read_only
  tasks:
   - name: Launch instances
     gcp_compute_instance:
       auth_kind: serviceaccount
       name: "{{ machine_name }}"
       machine_type: "{{ machine_type }}"
       project: "{{ project_id }}"
       zone: "{{ zone }}"
       network_interfaces:
       - network:
         access_configs:
         - name: External NAT
           nat_ip:
             address: "{{ node_1_ip }}"
           type: ONE_TO_ONE_NAT
       disks:
       - auto_delete: 'true'
         boot: 'true'
         initialize_params:
           source_image: "{{ image }}"
       tags:
         items:
         - jenkins-server
         - http-server
       service_accounts:
       - email: "{{ service_email }}"
         scopes:
         - "{{ service_account_scope }}"
       metadata:
         startup-script-url: "{{ startup_script_url }}"

```

At this point I have startup-script. This script deploy my public key to newly created VM instance:

```
#! /bin/sh
iniFile=/var/opt/inited.ini
if test -f "$iniFile"; then
    exit 0
else
    useradd ssh
    runuser -l ssh -c "mkdir -p ~/.ssh"
    runuser -l ssh -c "echo 'ssh-rsa <my public key>' >> ~/.ssh/authorized_keys"
    runuser -l ssh -c "chmod -R go= ~/.ssh"
    touch /var/opt/inited.ini
fi

```

Can I add public key when I create VM without using startup script? I read https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys But i don't understand how I can use it in my playbook.

# Answer
As per the link, You can add keys via metadata. You can try the following.

```
   metadata:
     ssh-keys: "[USERNAME]:ssh-rsa [NEW_KEY_VALUE] [USERNAME]"

```

Replace \[USERNAME\] & \[NEW\_KEY\_VALUE\] with actual key value.
> 1 votes

# Answer
use `ssh-keys` in metadata, e.g.:

```
    - name: Ensure instances
      google.cloud.gcp_compute_instance:
        name: "{{ item.name }}"
        machine_type: "{{ item.machine_type }}"
        disks:
          - auto_delete: true
            boot: true
            source: "{{ disk }}"
        network_interfaces:
          - network: "{{ network }}"
            subnetwork: "{{ subnet }}"
            access_configs:
            - name: External NAT
              nat_ip: "{{ address }}"
              type: ONE_TO_ONE_NAT
        zone: "{{ item.zone }}"
        metadata:
          ssh-keys: "root:{{ lookup('file',  'you_id_rsa.pub') }}"
        tags:
          items:
            - "{{ gcp.project }}"
        project: "{{ gcp.project }}"
        auth_kind: serviceaccount
        service_account_file: "{{ gcp.service_account_file }}"
        state: present

```
> 0 votes

---
Tags: ansible, gcp, centos
---


# Question
Title: How to fix wrong /etc/resolv.conf in kubernetes pods after creating a cluster with EKS eksctl with vpc-cni plugin?
So, i've created a kubernetes cluster in EKS with eksctl, ClusterConfig:

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig

```
metadata:
  name: exchange-develop
  region: us-east-1
  version: '1.19'

managedNodeGroups:

  - name: custom-bootstrap
    labels:
      worker: default
    instanceType: m5.large
    desiredCapacity: 2
    minSize: 2
    maxSize: 2
    ami: ami-00836a7940260f6dd
    tags:
      'k8s.io/cluster-autoscaler/enabled': 'true'
      'k8s.io/cluster-autoscaler/exchange-develop': 'owned'
    iam:
     attachPolicyARNs:
        - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
        - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
        - arn:aws:iam::658464581062:policy/eks-csi-driver-policy
        - arn:aws:iam::aws:policy/ElasticLoadBalancingFullAccess
        - arn:aws:iam::658464581062:policy/ALBIngressControllerIAMPolicy
        - arn:aws:iam::658464581062:policy/ExternalDNSPlicy
        - arn:aws:iam::658464581062:policy/eks-cluster-autoscaler
    # maxPodsPerNode: 110
    overrideBootstrapCommand: |
      #!/bin/bash
      /etc/eks/bootstrap.sh exchange-develop --kubelet-extra-args '--node-labels=eks.amazonaws.com/sourceLaunchTemplateVersion=1,alpha.eksctl.io/cluster-name=exchange-develop,alpha.eksctl.io/nodegroup-name=custom-bootstrap,eks.amazonaws.com/nodegroup-image=ami-00836a7940260f6dd,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=custom-bootstrap,worker=default,eks.amazonaws.com/sourceLaunchTemplateId=lt-0dae52a718d4ba6e5 --max-pods=110' --b64-cluster-ca $B64_CLUSTER_CA --apiserver-endpoint $API_SERVER_URL --dns-cluster-ip $K8S_CLUSTER_DNS_IP --use-max-pods false

availabilityZones: ['us-east-1c', 'us-east-1d']

iam:
  withOIDC: true

vpc:
  cidr: 10.10.0.0/16
  clusterEndpoints:
    publicAccess: true
    privateAccess: true

addons:
- name: vpc-cni
  version: '1.10.1'
  attachPolicyARNs:
    - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy

```

Then I can see the pod IP's are different from the vpc cidr, after recovering everything from another development cluster with Velero, there is no DNS resolving, so when checking the contents of `/etc/resolv.conf` in any pod the content is:

```
nameserver 10.10.0.2
search ec2.internal
options timeout:2 attempts:5

```

When checking dns-service endpoints:

```
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
kube-dns         ClusterIP   172.20.0.10      <none>        53/UDP,53/TCP   21h

```

Endpoints:

```
Name:         kube-dns
Namespace:    kube-system
Labels:       eks.amazonaws.com/component=kube-dns
              k8s-app=kube-dns
              kubernetes.io/cluster-service=true
              kubernetes.io/name=CoreDNS
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2021-12-06T19:38:03Z
Subsets:
  Addresses:          10.10.34.2,10.10.61.97
  NotReadyAddresses:  <none>
  Ports:
    Name     Port  Protocol
    ----     ----  --------
    dns-tcp  53    TCP
    dns      53    UDP

Events:  <none>

```

# Answer
Related issue: https://github.com/awslabs/amazon-eks-ami/issues/636

So, not specifying `--dns-cluster-ip`, `--b64-cluster-ca` and `--apiserver-endpoint` fixed the DNS issue.

Final bootstrap command:

```
  /etc/eks/bootstrap.sh exchange-develop --kubelet-extra-args '--node-labels=eks.amazonaws.com/sourceLaunchTemplateVersion=1,alpha.eksctl.io/cluster-name=exchange-develop,alpha.eksctl.io/nodegroup-name=custom-ami-bootstrap-ssh,eks.amazonaws.com/nodegroup-image=ami-0082fe83ca6d7cf7d,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=custom-bootstrap,worker=default --max-pods=110' --use-max-pods false

```
> 1 votes

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


# Question
Title: How to test provisioning and configuration in Ansible setup?
Looking at trying to build some resilience into our Ansible setup which deals with provisioning and configuration.

I understand a few methods of testing on the configuration side of things but I'm wondering how best to implement testing on the provisioning side of things, and if there are any tools which can help with this type of implementation.

Currently a lot of our testing is done serially during the playbook which makes a lot of sense for stuff like "has service come up; is the vip available; has this async task finished" but what really concerns me is our ability to manage drift of configuration at both the application and provisioning layer (such as VM configuration). I'm aware Ansible isn't the best tool for working with configuration drift but I'm curious to see your own opinions.

If you have something to fully automate the process even better. (we have a few ugly scripts which report back in slack daily).

**Note**: Right now we have a few conditions where a reprovision might occur (e.g. rebuild from backup, critical systems issue) but typically it just loops through some of the ansible configuring tasks and thinks no more of it.

# Answer
Some options out there..

**Testing tools:** Sorted by github stars

* Serverspec \- Ruby, most popular tool out there, built on ruby's rspec
* Goss \- YAML, simple, \<10MB self-contained binary, extremely fast, can generate tests from system state
* Inspec \- Ruby, think of it as an improved serverspec, almost same syntax, made by the chef guys. Built to be easier to extend than serverspec
* Testinfra \- Python, has the cool feature of being able to use Ansible's inventory/vars

**Major differences between them:**

Ultimately, I would suggest spending a day experimenting with all of them to get a feel for them before deciding for yourself.

* With the exception of Goss, all the frameworks can run against a remote machine (ex. over ssh). Goss only runs locally or in docker w/ dgoss.
* All frameworks can be run locally on a server, but require Python or Ruby to be installed or embedded. Inspec provides a self-contained \<150MB bundle with an embedded version of ruby. Goss is a single \<10MB binary with no external dependencies.
* Goss has built in support for nagios/sensu output, this allows for easier integration with monitoring tools.
* Goss tests tend to be simpler, but less flexible since it's based on YAML. Other frameworks allow you to leverage the full power of the underlying language Python/Ruby to write tests or extend the tool's functionality. (simplicity vs flexibility)
* Goss allows you to generate tests from current system state
* Testinfra to my knowledge is the only one that has built-in support for ansible inventory and variables
* Inspec is backed by Chef

**Continuous/divergence testing:**

* Chef Compliance \- works with inspec to continuously test your servers, paid product
* Goss \- Can be easily hooked into Nagios or Sensu. Also, supports exposing server tests as an http endpoint.

**Testing harnesses for development:**

* kitchen \- Testing harness tool, launches instance, runs config management code, runs test suite. Made by the chef guys
* Molecule \- Similar to test kitchen, but written specifically for ansible

***Full Disclosure:*** *I'm the author of goss*

**UPDATE:** InSpec 4.x or above uses a mixed commercial / open source license - see comments.
> 24 votes

# Answer
The two tools I've seen for this are InSpec and ServerSpec. Serverspec is a Ruby-based tool that builds on RSpec. InSpec is inspired by RSpec and ServerSpec.

I've used ServerSpec. It's cool, but maybe not 100% stable. I've had problems with testing for specific versions of software on Ubuntu.

I've read the InSpec docs but haven't dug in deep. It does essentially the same thing as Serverspec.

Judging by the Github commits, it looks like work on ServerSpec has tailed off somewhat, whereas InSpec is just getting ramped up.

**UPDATE:** InSpec 4.x or above uses a mixed commercial / open source license - see comments.
> 12 votes

# Answer
When using configuration management tools, such as Ansible, the tool itself would be responsible preventing configuration drift. Once you used Ansible to set a certain configuration, repetitive execution of Ansible will ensure your configuration is as you defined it to be. This also requires your Ansible code to be written in a manner which is idempotent.

Given the above, testing provisioning can be achieved by executing your Ansible playbooks in a loop from some server. For example, a cron job, or Jenkins, can execute the playbooks every 30 minutes and report back on any failure. Having no failures means that your configuration is in check, having failures means that there is a problem getting servers into your *desired state*.

In a case where you cannot trust your code to be written as idempotent, and thus you cannot really execute Ansible repetitively in a loop from an automatic server a workaround exists. You can do the same as above (run Ansible in a loop) but use its *dry run* mode. Each time Ansible reports that changes are required, the Jenkins job (or cron job) can notify you that your provisioned configuration has been altered and servers are not in their *desired state*.

To make sure that your Ansible code is actually doing what you think it should be doing, the solutions mentioned by Dave Swersky apply. Both InSpec and Serverspec are tools that verify in a *different* way that your playbooks actually does what you mean. A great way to execute these kinds of tools in test environments (even docker containers) is to use kitchen.ci which handles all the glue between the various infra unit testing tools, and execution of your playbooks/modules/cookbooks.

Kitchen.ci was originally used to test Chef cookbooks, but plugins exist for Ansible and other CM tools as well.
> 11 votes

# Answer
Test Kitchen has a kitchen-ansible provisioner plugin for testing of Ansible code. It isn't as deep as the Chef integration but it does get the job done for most cases. There is also the more recent Molecule project which is a dedicated Ansible testing system.
> 6 votes

# Answer
You can track configuration/infrastructure discrepancies/drift using Outthentic, it's easy to create a test suite to "fix" desired state and re-run it every time you need to track undesired changes.
> 0 votes

# Answer
It is usual to measure the code coverage for your source code written in python, Java, and so on. On the other hand, we usually do not measure the coverage for an Ansible playbook. Kirby is the tool to support this.
> 0 votes

---
Tags: testing, ansible, configuration, provisioning
---


# Question
Title: Python not connecting to mongodb in docker container
I have a simple python script which fetches certain values from the mongodb database. The script works fine on my local machine(host machine) but when i containarized my aplication it doesnt work. Here is my docker file.

```
FROM python:3.8-slim-buster
WORKDIR /app
COPY mysript.py .
RUN pip3 install pymongo
CMD [ "python3", "myscript.py"]

```

My python code

```
from pymongo import MongoClient
client = MongoClient("mongodb://userName:password@localhost/sampledb")
db = client.sampledb
tutorial1 = {"title": "Working With JSON Data in Python","author": "Lucas"}
tutorial = db.sampledb
result = tutorial.insert_one(tutorial1)

for doc in tutorial.find():
  print(doc)

```

This code works fine on my local machine but not on the container. However i get an error like

`pymongo.errors.ServerSelectionTimeoutError: 192.168.1.12:27017: [Errno 111] Connection refused, Timeout: 30s, Topology Description: <TopologyDescription id: 61b38be61c25e1ffbb4b9b0f, topology_type: Unknown, servers: [<ServerDescription ('192.168.1.12', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('192.168.1.12:27017: [Errno 111] Connection refused')>]>`

I have tried allowing by docker container IP by ufw firewall since its a connection refused issue but it doesnt work. I have also tried by changing the `localhost` field from the python code to docker container ip but that also doesnt helped me.

Does someone has any insights on this? Any help would be appreciated.

# Answer
> 1 votes
Are you using dockerized Mongodb like this?

https://hub.docker.com/\_/mongo

you must replace localhost in this line of code with mongodb container name:

```
client = MongoClient("mongodb://userName:password@<mongodb cointaner name or ip>/sampledb")

```

---
Tags: docker, python
---


# Question
Title: What would be the monthly hosting cost for eSchool Smart System
I have no idea about DevOps. Sorry in advance if the question is something not relevant.

> I have to propose a cost of yearly/monthly for a system. The system will have two versions. Web (React & Laravel separate projects) & App (Android). Initially the eSchool Smart System beta version will be launched 10000 Schools where there will features such as for different kind kf users Admin, Student, Teacher, Parents. Besides there will be real-time messaging feature.

Based on this brief what will be the approx cost per month/year to host the system?

Last but not the least, can anyone share the details configuration such as server, space, etc things.

Thank you.

# Answer
> 1 votes
It depends on how much storage your school needs for storing files and concurrent requests that come from your web and mobile application users.

You can use infracost to estimate cost on different cloud services.

---
Tags: amazon-web-services, azure, linux, servers
---


# Question
Title: How do I setup a script to run on a schedule in a clean & professional way?
I have a small python piece of code that I want to run on a schedule. The dirty way to do it would be to just spin up an EC2 instance and use CRON to run the script.

But I was wondering if there's a better (cleaner) way to do this

Also I was wondering how to do the same but on Google Cloud as well as AWS

# Answer
AWS Lambda should be an obvious choice together with a a CloudWatch Event trigger https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/RunLambdaSchedule.html .

Running an EC2 instance may be reasonable in some scenarios as well. It would make sense for me if the trigger for example did some complex data manipulation on a reasonable small data set (fitting in memory on a bigger spot multi-core instance or something like that).

Running a Fargate task - may be reasonable as well.

If it is something close to the gcloud example I would go with Lambda + CloudWatch Event. All of this can be easily defined via CloudFormation template .
> 3 votes

---
Tags: amazon-web-services, gcp
---


# Question
Title: Are Grafana alerts handled if Dashboard is closed?
I am using Grafana Stack Enterprise (on-premises) to monitor my servers via Prometheus. I created some alerts in dashboard panels. Are these alerts processed if I close my browser that has the dashboard open? Or do I need to leave the browser & dashboard open?

# Answer
> 3 votes
If those Dashboard/Panels are saved, everything will be processed. You don't need to have it opened.

---
Tags: grafana
---


# Question
Title: Why do I get "Connection Refused" when attempting to connect to IPFS API using HTTP?
Created a Digital Ocean Ubuntu 20.04 droplet and setup an IPFS server node in it based on this tutorial.

If I run the following command in the server

> ipfs swarm peers

I get the expected results

In addition, according to the documentation

> Every command usable from the cli is also available through the HTTP API. For example:
>
> ipfs swarm peers
>
> curl -X POST http://127.0.0.1:5001/api/v0/swarm/peers

so, as I try

* In Postman

> Error: connect ECONNREFUSED 164.92.254.19:5001

* In curl

> curl: (7) Failed to connect to 164.92.254.19 port 5001 after 2295 ms: Connection refused

---

For reference, here's the firewall

and as you can see TCP 5001 is open.

# Answer
Based on a tip from the Reddit user techiesaravana who says

> Hi, you have to edit ipfs config file you need to change the Address field to
>
> "/ip4/0.0.0.0/tcp/5001"

I was able to solve the issue. To do so, I ran

```
ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001

```

and then

```
systemctl restart ipfs

```

Now I get the expected result
> 1 votes

---
Tags: networking, api, curl, firewall, ipfs
---


# Question
Title: How to add Grafana Stack alerts to other graph types?
I am using Grafana 8.3.0, on-premises. When I create dashboard panels of type Graph (old), I get an Alerts tab and I can create alerts. But other graph types don't have that. What am I doing wrong?

Also, when I go the Alert Rules page, it says "You are using the legacy Grafana alerting." However, I don't see any way of creating alerts other than on the Graphs (old) panel Alerts tab. What does that mean that I am using legacy alerts, and how do I create alerts the "new" way?

# Answer
> 0 votes
You create alerts only via Graphs, that's how all my alerts are built or you can use Prometheus Alertmanager(it's more flexible), so you are doing nothing wrong. I am not sure how it works on-premise for the configuration of legacy alerts as I am using Grafana on EKS. Can you please check the documentation for migrating from legacy alerts, it is possible that you need to disable the legacy alerts and enable the new ones: Link to documentation.

---
Tags: grafana
---


# Question
Title: How do I force Packer to use Azure client secret in GitHub Actions workflow?
I use the following yml workflow in GitHub:

```
- name: Packer Build
  run: packer build -force -var 'client_id=${{ secrets.AZURE_CLIENT_ID }}' \
                           -var 'client_secret=${{ secrets.AZURE_CLIENT_SECRET }}' \
                           -var 'subscription_id=${{ secrets.AZURE_SUBSCRIPTION_ID }}' \
                           -var 'tenant_id=${{ secrets.AZURE_TENANT_ID }}' \
                           -on-error=abort ubuntu.json

```

The Azure service principal credentials are stored as GitHub repository secrets. I can successfully build the image from my local machine using the same credentials as zsh environment variables:

```
-> % packer build -force foo.json
azure-arm: output will be in this color.

==> azure-arm: Running builder ...
==> azure-arm: Getting tokens using client secret
==> azure-arm: Getting tokens using client secret
    azure-arm: Creating Azure Resource Manager (ARM) client ...

```

However, in the GitHub workflow, Packer tries to use Managed Identity, instead of the service principal and fails with the following error message:

```
azure-arm: output will be in this color.
==> azure-arm: Running builder ...
==> azure-arm: Getting tokens using Managed Identity for Azure
Build 'azure-arm' errored after 146 milliseconds 736 microseconds: adal: Refresh request failed. Status Code = '400'. Response body: {"error":"invalid_request","error_description":"Identity not found"} Endpoint http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F

```

# Answer
The solution was to declare the variables in the json template used by Packer build command. Like this:

```
{
  "variables": {
    "azure_cd":      "{{env `azure_cd`}}",
    "azure_ct":      "{{env `azure_ct`}}",
    "azure_td":      "{{env `azure_td`}}",
    "azure_sd":      "{{env `azure_sd`}}"
  },

  "builders": [{
    "type": "azure-arm",
    <etc..>

```
> 1 votes

---
Tags: azure, packer, github-actions
---


# Question
Title: Deploying microservices in a consistent way using different gitlab repositories
I'm looking for a good organization to deploy our solution consisting in multiple apps using Gitlab and K8S.

Our SaaS app that is made of :

* A backend app, mostly our API (django)
* A user app (React)
* An admin app (React)

Both frontend apps are connected to the API.

Currently the backend and user apps are in the same gitlab repository, and are deployed using a CI/CD pipeline that builds the apps, builds the docker images, and deploy them to K8S using a Helm Chart. The Helm Chart is located in the same repo.

I recently added the admin app in another gitlab repository and I'm concerned about keeping all apps consistent, that is to say, both frontend apps have to compatible with the API.

I'm thinking about adding another repository especially for the deployment (let's call this Deploy Repo). This repo could contain:

* 3 git submodules, one for each sub app,
* The Helm chart,
* Other files related to deployment

I thought about using git submodules to be able to have separate projects. The devs would update the right versions in the Deploy Repo when a service is ready to be deployed.

The push would then trigger the CI/CD pipeline, build all apps, and deploy all together using the Helm Chart.

Is this a good idea to use submodules like this ? What could be the best practice to link multiple projects together ?

I'm also concerned about how I could do to build only the sub project that has changed instead of all projects.

I have seen that it could be possible to link the pipelines of all subprojects together, and use artifacts to pass the needed files, but I'm not sure if this is a good solution.

# Answer
I'll give some general suggestions and specific example how we are doing it - hope it will help.

1. First of all, your idea to have a separate deployment repository is good and it is considered best practice in most cases.
2. Next, it makes more sense to organize things on artifact level rather than code level - essentially, your deployment repository would have records of artifacts rather than code pointers via say git submodules. Personally, I try to stay away from git submodules whenever possible as they complicate things a lot.
3. To elaborate on the above, each of your existing individual repositories would produce artifacts (docker images) via CI, place this artifacts to some registry, and then you would reference those artifacts in your deployment repository.
4. Now, the basic ways of maintaining artifact changes in deployment repository is manual edits of artifact identifiers, which can be simplified by referencing via tags. I.e., you reference specific artifact as myartifact:2 - and then all version 2 artifacts would automatically make it to release. Say you start with 2.0.0, then add 2.0.1 - it will be picked accordingly. Note, that referencing via tags is fine for testing, but not recommended for production - for production we always recommend specific referencing via sha256 digest of the image which ensures uniqueness and immutability.
5. To simplify the above tasks, people may put all artifact images into helm values files or use Kustomization with all image identifiers in one place. Some pull request logic may also be put on top (which is not always needed in the fully automated way below).
6. Finally, there are fully automated ways. The way we do it is we use automation via Reliza Hub - tool we are working on - to glue everything together. So in the nutshell it tells your helm chart what artifacts to use in the automated way.
7. Here is my toy project that shows various paths around the concepts above: https://github.com/taleodor/mafia-deployment
> 1 votes

---
Tags: kubernetes, continuous-integration, gitlab, helm
---


# Question
Title: How To Change the Default Dropdown Pipeline in Azure Pipelines
When I run a pipeline in Azure DevOps, I notice that the dropdown defaults to the master branch. I want it to default to the develop branch. How do I change this?

Picture for context:

# Answer
In short: you can change the default branch in the 'Get Sources' section of the pipeline settings screen.

In long:

1. from the pipeline summary screen, press the *Edit* button to load the Edit screen
2. from the hamburger menu at top right, select *Triggers*; this loads the pipeline settings screen
3. in the settings screen, select the YAML tab over on the left
4. in the listing below, select 'Get sources'
5. in the edit pane to the right, there is a picker for 'Default branch for manual and scheduled builds', which will be ordinarily set to 'master' (or 'main'). Change this to 'develop' and save.

The next time you manually queue up a pipeline run, the branch picker will default to 'develop'; but note that this also affects scheduled pipeline runs too, so be careful if you have a schedule.
> 1 votes

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


# Question
Title: YAML based azure build pipeline to run particular tasks based on condition?
Need to create a YAML based azure build pipeline i.e, need to run particular tasks like only build step when it is PR automated and when the same pipeline manually run it should run build task along with archive and publish artifact tasks

# Answer
> 1 votes
Yes; you can use the Build.Reason pre-defined variable in a task condition, like this for example:

```
condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))

```

---
Tags: azure-devops, azure, azure-pipelines, build-pipeline, yaml
---


title: Ingress vs Load Balancer

text:
# Question
Title: Ingress vs Load Balancer
I am new to kubernetes and I am trying to expose an application publicly. I am using Scaleway as the cloud provider (if it matters).

From what I understand, there are multiple ways of doing this.

1. Create an Ingress Controller

By doing this, the ingress exposes a nodes IP address and port and forwards all requests to the attached service.

I pointed the DNS record to the publicly exposed IP.

SSL certificate is created using cert-manager and it seems to work great with the ingress controller meaning that the certificate is automatically created and attached to the ingress resource.

How do you manage DNS records when the cluster has multiple nodes which can be deleted / created automatically?
2. Create a Load Balancer type service

This creates a cloud provided Load Balancer which internally is configured to route all traffic to all nodes from the cluster.

With this approach I can point the DNS records to the Load Balancer IP which in turn can be configured to preserve the public IP, meaning that cluster nodes can be attached / removed and it will not affect the DNS records.

But I do not know how to add a SSL certificate using this approach. Any thoughts?

Which of the two approaches is best suited for exposing an application keeping in mind the DNS management and SSL certificates?

# Answer
> 3 votes
After talking with the support staff from the cloud provider, reading through the docs and looking at how other cloud providers do it, I believe that both of them are needed.

In order to have a simple DNS zone management, you need to expose all your cluster nodes in some way and that way is with an external LoadBalancer.

The LoadBalancer makes sure to always point to all the cluster nodes even when there are changes to the nodes themselves (add / remove). This way you can update the DNS zone for the domain you want by pointing to the LoadBalancer IP. Of course, you will need to make sure that this IP will not change.

Since now there is a way to route external traffic from your custom domain to the kubernetes cluster, you need to know where to redirect that traffic.

Here comes the Ingress Controller.

With it you can forward traffic based on host name, for example, in order to reach your desired Service.

Comparing two cloud providers and their approach for publicly exposing an application, I found that both of them are using an external LoadBalancer together with an IngressController:

1. Scaleway

In order to expose all cluster nodes through a LoadBalancer you need to create a Service with the following:

```
spec:
  type: LoadBalancer
  ports:
    - port: 80
      name: http
      targetPort: 80
    - port: 443
      name: https
      targetPort: 443

```

`targetPort` is required to be those exact ports.

After LoadBalancer is created you can use its IP address for the DNS Records.

Now, you can create the Ingress Controller to forward traffic to Services.

2. AWS

You can create an Ingress Controller which itself creates an AWS Application Load Balancer.

The ALB does not have an IP, instead it relies on a CNAME Record.

Both of them are using an external LoadBalancer to forward traffic to the cluster and both of them are using IngressController to redirect traffic to Services.

I believe this is the way of publicly expose an application behind a kubernetes cluster.

# Answer
> 1 votes
A LoadBalancer is a cloud specific resource, you wouldn't have a LoadBalancer if you had kubernetes running on a raspberrypi, for example. Instead you would have to provision your own using something like metalLB.

When you create a LoadBalancer in aws, it creates a NLBenter link description here, a resource external to the cluster.

An Ingress type is a way of routing requests to the correct services.

So, your request would go through:

1. Internet - going all the way from your browser to your cloud provider
2. NLB (LoadBalancer) - on your cloud provider network
3. VM (ec2) - routed from the NLB
4. Ingress - finds the correct service to proxy the request to
5. Service - Also a load balancer, but internal to the cluster, find the deployment/statefulset, etc and gets the replicaset and picks a pod to route the request to
6. Pod - receives the request
7. Container - processes the request

And that's not even the most complex setup. You can add ambassadors, sidecars, MTLs, VPNs. Things can go crazy.

Here's a meme for clarification:

---
Tags: kubernetes, load-balance, ingress, ssl
---


# Question
Title: Jenkins installed on aws unable to launch on browser
I have a fresh aws instance with Ubuntu 14 installed.

I am trying to install and run jenkins on it. I did the following steps.

Installed java8

```
wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo apt-get update
sudo apt-get install jenkins

sudo apt-get update
sudo apt-get install jenkins

```

After that I checked the status of the Jenkins server

```
sudo service jenkins status

```

The response was:

```
Jenkins Automation Server is running with the pid 8355

sudo netstat -ntulp | grep 8080
tcp6       0      0 :::8080                 :::*                    LISTEN      8356/java

```

However, when I go to ipaddress of `<aws_instance_ip_address>:8080` the page does not load.

Going to `<aws_instance_ip_address>` opens the Ubuntu Apache default page.

What do I need to do for Jenkins to launch from browser?

# Answer
> 10 votes
It seems your have not opened your 8080 port in Security Groups in AWS.

Steps:

1. Go to AWS console
2. Click `Security Group` and select the security group that you have assigned to your EC2 instance.
3. Click `Edit Inbound Rules`
4. Add a `Custom TCP Rule` and add `8080` in the `Port Range`.
5. You will now see Jenkins rise from the grave :) i.e. first time installation screen.

P.S.: My Friend, if you have reached till Step 5, you know what to do next ;)

# Answer
> 2 votes
I had reposted this question in stackoverflow. https://stackoverflow.com/questions/46339167/jenkins-installed-on-aws-unable-to-launch-on-browser

The answer in comment "open the port 8080 in Ec2 security groups" resolved the issue for me.

# Answer
> 0 votes
I hope this post might help you with your question. Windows Azure Virtual Machine - Opening a port **This is for windows**

# Answer
> 0 votes
It seems your have not opened your 8080 port in Security Groups in AWS.

Steps:

Go to AWS console

Click ***Security Group*** and select the security group that you have assigned to your EC2 instance.

Click Edit ***Inbound Rules***

Add a ***Custom TCP Rule*** and add ***8080*** in the Port Range.

You will now see Jenkins first time installation screen.

---
Tags: jenkins, amazon-web-services
---


title: SQL Server database default template

text:
# Question
Title: SQL Server database default template
I'm creating a microservices architecture.

Each service needs its own database, so I've created an SQL Server resource in my Azure's Resource Group.

But the databases are created code-first by the services when they are deployed.

In Azure, it results with a newly created database attached to my SQL Server, and so in my Resource Group. Exactly what I want.

But unfortunately, the database configuration is the raw default of Azure, with 32GB and costs me a lot more money than it should.

I don't need more than 100mb per database and I can even pick the "serverless" Computer tier option to pay lesser.

So I've created a template of database and now I'm trying to assign it as the default template used by the SQL Server resource whenever a microservice creates a new database.

Is it even possible ?

# Answer
> 1 votes
ARM is the natural tool for templating an azure resource. I'd suggest structuring your solution so that:

1. your DB is deployed using an arm or bicep template, using the Microsoft.Sql/servers/databases resource type. That gives you the control to assign a database size, or include it in a different tier, etc.
2. your microservice follows up by taking the fresh database and building out the schema but without affecting the database size etc.

---
Tags: azure-devops, sql
---