Kubernetes: How to expose a Pod/Deployment to the Nodes Network Ok, let's assume I've got the following theoretical setup:

I want to somehow assign IP-Addresses accessible by the PCs on the left to my pods. I can set routes etc. as I need since this setup is purely for practice. My goal is for every Pod to be able to expose any service (HTTP(s)/FTP/...) on any port. E.g.: :22, :22 for SSH

My first thought was to create ClusterIPs for every pod and somehow use ingress to assign IPs to those services, but as I later found out this is not what ingress is intended for.

My next step was to look at LoadBalancer-type services and this is where I'm currently at. My current impression is that they somehow only work with AWS/Google Cloud/Other providers and always expose those selected services to the internet, which is not my intention. I only want them to be accessible from my internal network.

Any input would be appreciated.

Some clarification first,
the ClusterIP is only accessible inside the cluster this is not the right choice to solve your problem and the LoadBalancer depends on the integration with your network, real or virtual, to generate the correct resources and assign an IP address.

With that said, an easy way open a service port should be to use services of type NodePort it assigns a port directly on the machine, the same way you do when you open ports on a Linux machine, but with the difference that all the process is managed by Kubernetes. In that scenario, you only need to worry about the routes between the networks managed on your router.

You have more info about NodePort on the official Kubernetes documentation here

UPDATED

As per the last comments, for the use case, the use of NodePort should work and probably is a good option to use some DNS management like external-dns to not worry about how to setup the right IP.


Releasing so many changes at once to production My company has a mobile app which we release a new update every 2-3 weeks. For each release, there are about 50-60 Jira tickets attached. The amount of code change between the release are very high. We do not follow any CI/CD, so releases happen once or twice every month after approval from CAB.
Is having too many changes in a single release a bad way of release management?

This question as it is posed is quite leading - the use of adjective "bad" to describe what you are doing implies that there is a "good" way. Nobody can answer whether your process is "good" or "bad" but you, and it should be judged on the effectiveness of the process. Perhaps this way of doing things is good for your environment...
However, what we can say is that the situation you describe goes against the principles of continuous delivery and continuous integration.
For example, describing the principle of "work in small batches",
the Continous Delivery website states:

In traditional phased approaches to software development, handoffs from dev to test or test to IT operations consist of whole releases: months worth of work by teams consisting of tens or hundreds of people.

This sounds like your situation.
It goes on to state:

In continuous delivery, we take the opposite approach, and try and get every change in version control as far towards release as we can, getting comprehensive feedback as rapidly as possible.
Working in small batches has many benefits. It reduces the time it takes to get feedback on our work, makes it easier to triage and remediate problems, increases efficiency and motivation, and prevents us from succumbing to the sunk cost fallacy.

So, by this comparision, yes, your release management is "bad", because it doesn't work in small batches, or continuously. (Again, with the caveat that any process that is executable effectively is a good process).
Another widely-used reference text, the Google Site Reliability Engineering Book has a whole chapter on release engineering. It says:

We have embraced the philosophy that frequent releases result in fewer changes between versions

Your process seems to run counter to this statement, and though you don't specify what level if testing or canary deployments you use, one may surmise from the fact that there is no continuous integration that this is very small, if any. Therefore, by "SRE logic", every new deploy is high-risk, because it contains a large amount of untested changes.
There is another aspect which increases the risk in doing things "your" way. It is not reasonable to expect that a CAB will be able to make an informed decision on whether or not a given build should be released, without feedback on the performance or behaviour of the application in it's target environment (i.e. prod). They will be making decisions based on predictions and assumptions, rather than data.
For all these reasons, and probably many more, I think the consensus of this community would be that the answer to your question would be "yes, this is a bad way of doing release engineering".
A better way would be to:

Have a minimum of testing in place, and work on extending that with every deploy
Start to automate the tests as far as possible and have clear documentation for how to test it when automation is currently infeasible.
delivery artifacts continuously and run canary deploys to a test environment; work on aligning  that environment as closely as possible with the production environment
Aim for the option of deploying any given build, and have a means for rolling back in the case of problems, to reduce the fear associated with deployment.

Smaller, and more deployments mean smaller changes at a time, which are easier to fix, and observing the deployment procedure continuously will give better insight into its reliability and where to improve things.
Automate, measure, improve. Repeat.


How do you simulate "sudo su " in Ansible? I have a server where my user is able to sudo to the root user without a password, and then the root user can sudo to a third user without a password.  However, my user cannot sudo directly to the third user without a password.

Ansible's become directive uses sudo in the traditional manner, i.e. the one that requires prompting for my password.

I've tried putting become_user: root on a block and become_user: <other-user> on a task inside that block, but it appears Ansible overrides the block's definition, rather than nesting the sudo calls as I hoped.

Note: this question has also been asked on StackOverflow, but since there's no solution I figured I would repost it here, which I think is the better site for it.

I met the same situation. I have login1 for my machine, passwordless sudo and login2, under which I should perform some actions. I did not solve it by ansible means. But I made such a workaround:

- name: "Install nvm"
  shell: sudo -u buildkite-agent bash -c "<my commands to be performed on behalf of buildkite-agent>"
  become: true

Such a case:

- name: "Install nvm"
  shell: sudo -u buildkite-agent <my commands to be performed on behalf of buildkite-agent>
  become: true

do not change home to buildkite-agent's home, i.e. uses /root as home.


Why Ansible skip items in inserafter? I have about 10 hosts that I run a playbook for them with serial:1. in this playbook there is this code which append output of all commands in one file:

    - name: copy the output to a local file
      lineinfile:
       dest: "{{ myshell_output4.stdout }}"
       line: "{{ item }}"
       insertafter: EOF
      with_items:
        - "########################################################"
        - "###############HOSTNAME:{{ inventory_hostname }}################"
        - "{{ myshell_output3.stdout }}"
        - "########################END#############################"
     delegate_to: localhost

it is always working for the first host but for others it only insert second and third line and skip first and last line. the out put of file is like this:

  ########################################################
  ###############HOSTNAME:12.15.1.1################
  (some output here)
  ########################END#############################
  ###############HOSTNAME:12.15.2.2################
  (some output here)
  ###############HOSTNAME:12.15.3.3################
  (some output here)
  .
  .

why this happen and how i can prevent it?

Apparently delegate_to and lininfile or blockinfile do not work properly together, https://github.com/ansible/ansible/issues/28313.

Module blockinfile

It seems redundant lines have not been written as you would expect. Eventually, blockinfile without a marker does the job.

- name: copy the output to a local file
  blockinfile:
    dest: "{{ myshell_output4.stdout }}"
    marker: false
    block: |
      ########################################################
      ###############HOSTNAME:{{ inventory_hostname }}################
      {{ myshell_output3.stdout }}
      ########################END#############################
  delegate_to: localhost

Concatenate files at the end

Alternatively, you can write to different files and concatenate those files after all tasks have run.

- name: copy the output to a local file
  copy:
    content: |
      ########################################################
      ###############HOSTNAME:{{ inventory_hostname }}################
      {{ myshell_output3.stdout }}
      ########################END#############################
    dest: tmp/{{ inventory_hostname }}
  delegate_to: localhost

- name: log files are concatenated
  assemble:
    src: tmp/
    dest: "{{ myshell_output4.stdout }}"
  delegate_to: localhost
  run_once: true

- name: tmp folder is absent
  path:
    src: tmp/
    state: absent
  delegate_to: localhost
  run_once: true

In case your local file myshell_output4.stdout does exist already and you want to append to an  existing file, you assemble the files tmp/* into tmp/assembled and the append them with lineinfile.

- name: append assembled to a local file
  lineinfile:
    dest: "{{ myshell_output4.stdout }}"
    line: "{{ lookup('file', tmp/assembled) }}"
  delegate_to: localhost
  run_once: true


Chef remote_file set maximum number of re-directions to zero I am trying to implement the below wget download command using chef remote_file resource. But I couldn't find a way to avoid the re-directions. The URL that I am trying to access may sometimes be redirected to my ISP bill reminder page. And chef remote_file resource downloads this bill reminder HTML page as a zip file.

wget -N  --max-redirect=0 http://www.someurl.com/file.zip

The chef recipe resource is

remote_file "#{node['download-zip-path']}/#{zip}" do
    source "http://www.someurl.com/#{zip}"
    action :create
    notifies :run, 'execute[unzip_file]', :delayed
end

The --max-redirect=0 flag in wget makes sure that there isn't any redirection to ISP page. I can achieve the same using ruby's open-uri or execute command resource but is there any native chef way to achieve this no/zero re-direction?

Found out that the remote_file resource couldn't handle redirects. Hence I had to write a ruby_block resource that makes use of 'Down' gem.

ruby_block 'download_openvpn_zip' do
    block do
        attempt = 2
        begin
            retries ||= 0
            tempfile = Down::NetHttp.download("http://www.someurl.com/#{zip},max_redirects: 0)
            FileUtils.mv tempfile.path, "#{node['openvpn-conf-path']}/#{tempfile.original_filename}"
        rescue Down::TooManyRedirects => e
            puts "\n \t ERROR: #{e.message}"
            retry if (retries += 1) < 1
        end
    end
    action :run
    notifies :run, 'execute[unzip_file]', :delayed
end


Deploying VMs using roles and hosts in Ansible based on operating system I'm having issues working out how to best apply hosts/roles to different operating systems in Ansible.

I'm currently using Ansible to generate Windows/Mac/Linux VMs, and each of the VMs have different roles which need to be applied to them.

I've read the best practices and have tried to follow them, especially to use the grouping method, but I'm still unsure as they mostly mention webservers and dbservers.

site.yml

- name: Apply common configuration to all nodes
  hosts: all
  roles:
    - common

- name: Configure and deploy test node 1
  hosts: build-test-node
  roles:
    - build-machine-test-1

- name: Configure and deploy test node 2
  hosts: build-test-node-2
  roles:
    - build-machine-test-2

environments/test/groups

[win_build_nodes]
win_build_machine_1
win_build_machine_2

[mac_build_nodes]
mac_build_machine_1

environments/test/hosts

win_build_machine_1   ansible_host=......
win_build_machine_2   ansible_host=......
mac_build_machine_1   ansible_host=......

environments/test/meta

[mac_build_nodes]
[win_build_nodes]

[win:children]
win_build_nodes

[mac:children]
mac_build_nodes

[linux:children]

[build_nodes:children]
win_build_nodes
mac_build_nodes

The environment/test/meta file I believe needs to be changed with the build_nodes:children, but I'm not sure what to. Previously I was just having the VMs have all the roles built to it with the following:

Old site.yml

- name: Apply everything
  hosts: build_nodes
  roles:
    - common
    - build-machine-test-1
    - build-machine-test-2

But then realised I didn't want everything being built on the same machine. Note, build-machine-test-1 and 2 both have separate Windows/Mac/Linux builds as they detect what to include based on the operating system.

Can anyone suggest a better way of separating the VMs based on operating systems?

So I managed to keep the same structure roughly, and managed to separate how the machines are generated, however still is a bit fuzzy and can probably be improved to be more efficient!

site.yml

- name: Apply common configuration to all nodes
  hosts: all
  roles:
    - common

- name: Configure and deploy test node 1
  hosts: build-test-node
  roles:
    - build-machine-test-1

- name: Configure and deploy test node 2
  hosts: build-test-node-2
  roles:
    - build-machine-test-2

environments/test/groups

[win_test_1_nodes]
win_build_machine_1

[mac_test_1_nodes]
mac_build_machine_1

[win_test_2_nodes]
win_build_machine_2

[mac_test_2_nodes]
mac_build_machine_2

environments/test/hosts

win_build_machine_1   ansible_host=......
win_build_machine_2   ansible_host=......
mac_build_machine_1   ansible_host=......
mac_build_machine_2   ansible_host=......

environments/test/meta

[win_test_1_nodes]
[mac_test_1_nodes]
[win_test_2_nodes]
[mac_test_2_nodes]

[win:children]
win_test_1_nodes
win_test_2_nodes

[mac:children]
mac_test_1_nodes
mac_test_2_nodes

[build-machine-test-1:children]
win_test_1_nodes
mac_test_1_nodes

[build-machine-test-2:children]
win_test_2_nodes
mac_test_2_nodes

This solution allows more test nodes to be generated with separate roles added to them, and can just be added to the correct group for the machine to be provisioned.


What are the pro and cons of SnowFlakes Servers, Phoenix Servers and Immutable Servers? I'm curious about a matrix like comparison on security/ease of management/forensic ability for each type of server. I may forget some more key features of each type also.

I've a general idea about the types but a reference matrix would be of help when choosing between them on some cases (when the automation become complex for the application for example).

To avoid concern about it being too broad, I feel that splitting it in multiples question would scatter the information and that a question about security comparison would need to compare each type also.

The term Phoenix Server was coined by a fellow of Martin Fowler, and all three terms described in short articles on Martin's bliki.

Snowflake Server
Phoenix Server
Immutable Server

The pros and cons of each such server are described in the articles. The main difference being in the way the server is managed.

Servers exist to fulfill the role of a container for some application(s). Since applications change often, it is often required to change some attributes of the container - such as packages, configuration, etc. It is also sometimes required to change attributes of the container itself because of external reasons, such as security vulnerabilities that require patches to be installed.

There are several ways to change an existing server:

Manually create the server initially, then keep changing its content (mutating) each time a change is required.
"Bake" an image for a server based on a recipe, usually in an automated way (not manually). Then create servers from that image. And repeat this process on every change.

The former is called Snowflake, while the latter is a practice that allows Phoenix and Immutable server types. Where Immutable states that no changes are made to an existing server once it was created, and Phoenix means that a server is destroyed completely and a new one is used to replace it during the change process.


Run integration test with ansible playbook using terraform provisioning Ok so I am totally new to devops! I am an experienced developer, but at my new job I have been tasked to automate CI/CD. Non-existing so far. Only CI with Travis.

So the ideal workflow is:
Push to CI -> build -> if successful provision an EC2 instance -> run integration tests

Our ideal architecture is to use terraform for provisioning and ansible for automation/config management. Scenarios down the road foresee continuous deployment and more stuff. So I need to get the basic building blocks right. This workflow seems like a good start.

I've searched for tutorials all day and, being beginner, I am totally confused.

As the goal is to fully automate the process, I am naively assuming that the ansible playbook would call a terraform provisioning role/task, and then continue by running all the steps for the integration tests.

But all I have found says to always run terraform init first and then terraform apply before switching to run a playbook, which seems cumbersome and not that "automated".

Can someone point me to a good resource describing how I can setup my desired workflow? Am I understanding things wrong?

You are right about Terraform having a plan-apply cycle which may not be that conducive to automation. The following has worked for me in similar situations:

Use Terraform to "develop" new versions of a base EC2 image.
Use Ansible playbooks to provision EC2 instances off a specific version of the image and run tests on them.


How to deploy a desktop application using Azure DevOps? I'm using Azure DevOps and I need a way to release an internal desktop application. Right now I have a pipeline ready and generating artifacts, but I don't see anywhere in the documentation how can I provide a release link to my users.

The documentation for how to build a desktop client in Azure DevOps is right here:

Build your .NET desktop app for Windows

However, at the end there is no information on how to proceed - in fact, the "Next steps" section provides links on how to deploy Web Apps or VMs, which are hardly relevant for desktop applications (there is also this issue which states this, but was closed with a "thank you, we've added this to our backlog")

So you want to deploy a desktop application to a Windows machine? Looking through the rest of the documentation, the following links may be helpful:

Windows Machine File Copy task
Build, test, and deploy .NET Core Apps

I can't tell for sure, but you might just be looking for a way for users to download the build artifacts. If that's the case, this link on Build Artifacts may help.


private subnets in an Auto Scaling Group on aws? I watched a video series wherein the author used 3 private subnets for his Auto Scaling Group, and I also read the premium answer on this forum wherein the author says that you can use both public and private subnets in an Auto Scaling Group:

https://acloud.guru/forums/aws-certified-solutions-architect-associate/discussion/-K_JalpbCBG_pUIbNc4k/vpc-private-subnet-and-autoscaling

  "When you create the "Auto Scaling Group" you will specify your VPC
  and as many of the related "Subnets" that you want to launch instances
  into - it does not matter if they are private or public it is entirely
  up to how you have designed your solution."

So I tried it. I use three private subnets in my Auto Scaling Group and the website does not load from the public DNS or the public IP. I notice the IP of the instance belongs to one of the private subnets, 10.0.4.135 (the subnet is 10.0.4.0). Also, the issue is not with Security Groups, because that instance above has a security group allowing all outbound traffic and inbound traffic from 80, 443 and 22.

Now if I used 3 public subnets, then the site will load! So what's the difference? The private subnet uses a NAT Gateway and the public subnet uses an Internet Gateway. It makes sense that traffic CANNOT go to this private subnet since there is no internet gateway to it; that's the whole purpose of having a private subnet.

So then why does the premium member state that an Auto Scaling Group can use both public and private subnets?

There is a range of common scenarios when you want to use private subnets to be used in an auto scaling group:

Your traffic is terminated by reaches your infrastructure on a  Elastic Load Balancers and your web server instances are behind the load balancer. This reduces the attack surface of the web servers.

( I think I started to use "terminate" since seeing it being used for SSL/TLS termination, ie the server(s) that hold the secure certificates. But because you could also use a Network Load Balancer at the "edge" of your infrastructure, I see now its not appropriate to use in this context)

Your auto scaled resources are actually not responding to outside traffic, for example if they are worker resources processing messages from an SQS queue.

There was a similar mention of both "public and private subnets" all over my LinuxAcademy exam preparation, depending on your thinking processes it may be straightforward to just say: "autoscaling can use subnets", but then this may confuse other people.


Ansible warning that host key has changed, even though I've taken multiple steps to prevent this warning I've followed the recommendations I could find to prevent this from happening.  I am using Vagrant, but once the boxes are spun, I'd like to do things with the ansible command sometimes.

$ grep host_key /etc/ansible/ansible.cfg
host_key_checking = False

$ grep kafka01 ./inventory
kafka01 ansible_host=127.0.0.1 ansible_port=2231 ansible_user='vagrant' ansible_ssh_private_key_file='/home/me/project/project/.vagrant/machines/kafka01/virtualbox/private_key' ansible_ssh_common_args='-o StrictHostKeyChecking=no'

$ export ANSIBLE_HOST_KEY_CHECKING=False
$ ansible kafka01 -m ping -i ./inventory

 [WARNING]: Unhandled error in Python interpreter discovery for host kafka01: Failed to connect to the host via ssh: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @    WARNING:
REMOTE HOST IDENTIFICATION HAS CHANGED!     @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!  Someone could be eavesdropping on
you right now (man-in-the-middle attack)!  It is also possible that a host key has just been changed.  The fingerprint for the ECDSA key sent by the remote host is
SHA256:jn5ClU5g566Gsvobf8Xc45DJnIiAllN+RJkg35Nf9KE.  Please contact your system administrator.  Add correct host key in /home/me/.ssh/known_hosts to get rid of this message.  Offending ECDSA key
in /home/me/.ssh/known_hosts:19    remove with:    ssh-keygen -f "/home/me/.ssh/known_hosts" -R "[127.0.0.1]:2231"  ECDSA host key for [127.0.0.1]:2231 has changed and you have requested strict
checking.  Host key verification failed.

kafka01 | UNREACHABLE! => {
.....

What's going on here?

Edit: No, I don't want to keep deleting the key.  I destroy/build these over and over again.  I want to find the correct, long-term solution.

You can add this in inventory:

ansible_ssh_common_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"

It's ignoring check host and setting /dev/null as Known host file.


Azure ARM Triggers (e.g. Resource Created, Resource Removed, etc) I am trying to find a way to trigger events on creation/removal of specific Azure Resources.
My goal is to add and/or remove these resources information to an App Gateway.
Can that even be done? My alternative would be to use a scheduled solution but I would love to avoid that.
Thanks in advance,

So you can use something like Azure Event Grid where you can listen to events from different types of Azure Resources and then that event could be listened to by a Webhook trigger which then can trigger your pipeline, see here:
https://docs.microsoft.com/en-us/azure/event-grid/overview


How to automatically remove a dead node from RabbitMQ cluster I am planning to create RabbitMQ cluster using Ansible on AWS VPC with Amazon internal load balancer as the frontend to point connections to it.

Any suggestion how to remove a dead node from RabbitMQ cluster based on autoscaling rule where nodes can go up and down, or if you are using spot instances?

When a node goes down, RabbitMQ does not remove it from the replication list automatically, I can see Node not running in the management UI.

I managed to join to the cluster a scaled instance automatically via Ansible and userdata.

Consider using the rabbitmq/rabbitmq-autocluster plugin:

  A RabbitMQ plugin that clusters nodes automatically using a number of peer discovery mechanisms:

  Consul,
  etcd2
  DNS A records
  AWS EC2 tags
  AWS Autoscaling Groups

There is a fair bit of configuration to plug in to get this setup including setting IAM policies and adding EC2 tags to the instances you want to be party to your cluster.

If you were to use AWS Autoscaling Groups then you would add the following to your rabbitmq.config:

[
  {rabbit, [ ... ]},
  {autocluster, [
    {backend, aws},
    {aws_autoscaling, true},
    {aws_ec2_region, "us-west-2"}
  ]}
].

If you are not using AWS Autoscaling Groups you can still achieve the desired result using tags on your EC2 Instances:

[
  {rabbit, [ ... ]},
  {autocluster, [
    {backend, aws},
    {aws_ec2_tags, [{"region", "us-west-2"}, {"service", "rabbitmq"}]},
    {aws_ec2_region, "us-east-1"},
    {aws_access_key, "..."},
    {aws_secret_key, "..."}
  ]}
].

With all of that said I strongly recommend using Consul by HashiCorp as your service discovery mechanism, in the long run, you get significantly more flexibility in terms of decoupling your parts of your system from each other.


Definition of "Done" for DevOps I've being recently interviewed for a DevOps position. One of the questions I was asked was:

  What is your definition of "done" in the DevOps context?

The question is rather broad, but, as I understand, the answer has to cover Automated builds & tests as well as Continuous Integration & Deployment & Delivery. I am looking for general principles and ideas that can be used to define "Done".

Instead of Continuous Integration and Continuous Delivery, I would define the definition of done as "Active Continuous Improvement at all levels of the organisation".

The other topics like automated builds, CI/CD, etc... these are just milestones and most definitely not the ultimate goal for the organisation in its DevOps efforts.

It does look like it might be "finished all DevOps" once you have an automated system with continuous integration. But in fact, even should you reach this stage, you will find plenty more to do.

Getting to a state where most people in the organization are constantly looking to continuously improve is extremely hard. Inertia often gets in the way, both existing inertia, and new inertia once some improvements were accomplished.

There is a lot to learn from Lean and from Theory of Constraints in this aspect. Both bodies of knowledge focus on the process of continuous/ongoing improvement and how to establish this process in an organization.


How do I make a redis container accessible through bridge networking from the host? I'd like to be able to connect directly to the redis container below:
root $
root $ docker images redis
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
redis               alpine              bd71e6db4a54        2 weeks ago         32.2MB
redis               latest              84c5f6e03bf0        2 weeks ago         104MB
root $
root $ docker run --name rd -d -p 99:99 redis:latest
ac4b8b2b032b2c2911f03fd4f6af649f470620cd29eb566b821e5ce738d9ac11
root $
root $ docker exec -ti --user root rd bash
root@ac4b8b2b032b:/data#
root@ac4b8b2b032b:/data# redis-cli
127.0.0.1:6379>
127.0.0.1:6379> exit
root@ac4b8b2b032b:/data#
root@ac4b8b2b032b:/data# exit
exit
root $
root $ docker network ls
NETWORK ID          NAME                    DRIVER              SCOPE
74c94db9195c        basexhttpnetwork        bridge              local
a5efbdf4bc39        bridge                  bridge              local
4b6586d1bc8c        frappe_docker_default   bridge              local
1b875368faa0        helloworld_default      bridge              local
3bc6659535b4        host                    host                local
e877e399bf78        none                    null                local
root $
root $ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                          NAMES
ac4b8b2b032b        redis:latest        "docker-entrypoint.s…"   6 minutes ago       Up 6 minutes        0.0.0.0:99->99/tcp, 6379/tcp   rd
root $

using the redis-cli tool from the host.  So I would need to add or attach the rd (for redis) container to the bridge driver?  Then specify an IP address and port from the host?

By default Docker uses the bridge network.
On a default Docker installation you can simply map a port to the container's service port.  The Redis Docker image exposes its service on port 6379 so you can do:
$ docker run --name rd -d -p 6379:6379 redis:latest
From your host you can now run use the redis-cli utility:
$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>


Always execute post statement in a jenkins pipeline when a conditional statement is met Although it seems counterintuitive, I would like to execute an always statement when a conditional is met. In my pipeline, my post statement should always destroy my AWS CloudFormation Stack if a variable is set to true. Below is the post statement which is not correct.

post{
    always {
        when {
            expression { DeleteStack == 'true'}
        }
        stage("Delete All Stacks") {
            steps {
                script {
                    withAWS(region:'us-west-2', credentials:'jenkins-deploy') {
                        def outputs = cfnDelete(
                            stack:"${CFTBatchStackName}",
                            pollInterval:1000)
                    }
                    withAWS(region:'us-west-2', credentials:'jenkins-deploy') {
                        def outputs = cfnDelete(
                            stack:"${CFTVPCStackName}",
                            pollInterval:1000)
                    }
                    withAWS(region:'us-west-2', credentials:'jenkins-deploy') {
                    def outputs = cfnDelete(
                        stack:"${CFTSelfDeleteName}",
                        pollInterval:1000)
                    }
                }
            }
        }
    }
}

Can I achieve this using a declarative pipeline?

According to the documentation, the when directive is only allowed inside a stage. You have to use the script directive if you want to use conditional statements:

post {
  always {
    script {
      if (DeleteStack == 'true') {
        // Destroy what you want !
      }
    }
  }
}


What are some clear benefits of running master/agent configuration management? Ansible seems to have a clear advantage over competition like chef and puppet because it is agent-less and saves a certain degree of overhead.

I have read several comparisons of the various configuration tools and while each tool has its own strengths and weaknesses, I realize that much of it is down to personal preference.

The benefit of being agent-less is a no-brainer but are there any advantages of the master/agent architecture with respect to configuration management tools?

I've found an interesting discussion on the topic configuration management pull vs push topology

One contributor writes that pull systems (master/agent) offer more flexibility and are easier to scale.


Can't hit redis using DNS name in multi-container pod on Kubernetes Can anyone shed some light on why this might not work? I can access redis just fine using the pod's IP address,
$ rdcli -h 10.152.183.65
10.152.183.65:6379>

but when I try to use the DNS name, I cannot connect.
$ rdcli -h dbbackupd.default.cluster.local
dbbackupd.default.cluster.local:6379> (error) Redis connection to dbbackupd.default.cluster.local:6379 failed - getaddrinfo ENOTFOUND dbbackupd.default.cluster.local dbbackupd.default.cluster.local:6379

Inside the pod that is trying to contact redis, I get the right-looking output when using the host command, so name resolution looks good:
$ host dbbackupd.default.svc.cluster.local

dbbackupd.default.svc.cluster.local has address 10.152.183.65

My theory is that because redis is in a multi-container pod, that dns is not routing it to the container properly. Here is my Service's definition in case that sheds light:
apiVersion: v1
kind: Service
metadata:
  name: dbbackupd
  labels:
    app: dbbackupd
spec:
  selector:
    app: dbbackupd
  type: NodePort
  ports:
    - name: redis-mq
      protocol: TCP
      port: 6379
      targetPort: 6379
    - name: sql-comm
      protocol: TCP
      port: 1433
      targetPort: 1433

You're using two different host names:
$ rdcli -h dbbackupd.default.cluster.local
$ host dbbackupd.default.svc.cluster.local

The one used with rdcli is missing .svc.


AWS SQS - use case for "short polling" When using event driven processing of work with AWS SQS and worker clients. the use of long polling is often recommended. AWS documents this here

Essentially when there are no message in the queue, the worker does not need to keep making requests to the queue (this reduces call costs), but new messages are still delivered immediately to a worker that is long polling.

Having build small systems a couple of times with SQS now, I question what the benefit of short polling is. I imagine it may be slightly faster, as only a subset of SQS servers are polled when short polling, but if that is the only downside, what sort of additional delay am I looking at? Does it depend on the number of messages I am processing? (Does SQS servers scale based on the number of messages?)

What other downsides are there, if any?

While you can benchmark this yourself, benchmark testing has shown that there isn't much of a difference in time between long and short polling when the queue is full.  Additionally, with long polling you always have data coming back unlike short polling.

As for when to use short polling the AWS FAQ covers this:

  For example, if your application uses a single thread to poll multiple queues, switching from short polling to long polling will probably not work, because the single thread will wait for the long-poll timeout on any empty queues, delaying the processing of any queues that might contain messages.

Additionally:

  ..if your application expects an immediate response from a ReceiveMessage call, you might not be able to take advantage of long polling without some modifications to your application.

If you don't want to deal with asynchronous queues and multiple threads handling the queues in your application then short polling may provide an easier development path (although you'll have to deal with empty responses).


Run docker applications within a kubernetes cluster As part of my architecture, I want to create a deployment/service on my kubernetes cluster which reads message queues and open dockerized subscribers and then subsequently relay message to the original subscriber (if its an RPC pattern).

I was wondering what would be the best workflow to ensure minimal latency (esp since some workflows are RPC).

I can create kubernetes JOBs but that would mean i read logs for the output of pods which would be relayed and then subsequently delete the job . But I worry this might be an overkill
I can volume share the docker socket and my service can then run my images using docker client. But I am not if thats the right way to do so given that i would like to have proper tracking/versioning of my docker images esp since nodes on clusters are disposable
Are there existing frameworks to handle my situation.

After reading your Q&A I think that you are looking for a message broker like kafka, rabbitmq or Amazon MQ. Please let me know whether this helps.


Use dynamic values for parameter-store in aws buildspec.yml for CodeBuild For my CodeBuild projects, I have a dev, staging and production project. Each project has an environment variable called $BUILD_ENVIRONMENT set to dev, staging and production, respectively. Each stage has its own key/value pair in Systems Manager Parameter Store. I want to use one buildspec.yml across all branches, so if I try to merge a branch or checkout a new branch, it does not copy hardcoded values in buildspec.yml. This is what I tried to do:

version: 0.2

env:
  parameter-store:
    SECRET_KEY_BASE: /myproject/$BUILD_ENVIRONMENT/secret_key_base

But it doesn't work. There is no interpolation done and I get the following error:

  Decrypted Variables Error Message: parameter does not exist:
  /myproject/$BUILD_ENVIRONMENT/secret_base_key

Since this is such a common use case, I am wondering if anyone found any type of solution to this?

I faced the same problem while using different SSH key pairs for different deployment environment. Usually I used to create different ssm variables per environment and then changed the name of ssm per git branch in buildspec.yml. That worked perfectly for me. For example, for deploying to stage environment i used the git branch "dev" which had following buidlspec.yml config
env:
  parameter-store:
    SECRET_KEY_BASE: "DEV_SECRET_KEY_BASE"

for "release" environment it was,
env:
  parameter-store:
    SECRET_KEY_BASE: "RELEASE_SECRET_KEY_BASE"

make sure you resolve merge conflicts between inter git branches before you apply.


Debug BackendConnectionErrors from Kubernetes Service LoadBalancer sesrvice We recently moved some of our production infrastructure to Kubernetes. Many pods are exposed through a LoadBalancer service on AWS. This creates an ELB, registers each node in the cluster with the ELB, and configures a node port to map ELB ports to pods. Our applications are able to connect via the load balancer, but amount of BackendConnectionErrors (as reported by cloudwatch) is 5-7x higher than request count. I'm not sure how to debug this.

The number of reported backend connection errors does not correlate with any application layer error metrics. This leaves me to conclude that it some sort of infrastructure problem perhaps being amplified by retries. However I do not know how to debug this issue.

My hypothesis is one or both of these:

Some weird AWS setting that is missing on the ELB for connection management
Nodes in the cluster have some sysctl setting or other networking config that's blocking the amount of connections coming over the ELB
Some intermediate piece of networking infrastructure messing with the connections.

My question is: how I can debug/trace some TCP/networking related metrics on the instances in the cluster?

More info about the CloudWatch metrics in question.

My solution to this problem was to rework my Services. The setup in my question had one K8s Service with ~10 ports. I reworked the setup to use one port per Service. The problem went away. I don't know why though. This makes me suspect something on the nodes themselves or some complexity in routing connections to the correct node port. I'm cautious of exposing too many ports again because of this.


jar file is not displaying in docker container I have an sbt project and i am creating its Jar using the  sbt publishLocal command and i want a docker image for that i am doing something like this

FROM hseeberger/scala-sbt:11.0.2_2.12.8_1.2.8

MAINTAINER Sara Waheed <sarawaheed3191@gmail.com>

WORKDIR /myproject

ADD . /myproject

# Define default command.
CMD ["sbt", "publishLocal"]

and i am building it docker build -t myproject:v1 and run it docker run myproject:v1
i have seen in the logs

[info] Main Java API documentation successful.
[info] Packaging /stripe-payment-account/target/myproject-1.0.1-javadoc.jar ...
[info] Done packaging.
[info] :: delivering :: com.test#myproject;1.0.1 :: 1.0.1 :: release :: Tue May 07 10:26:13 UTC 2019
[info]  delivering ivy file to /stripe-payment-account/target/ivy-1.0.1.xml
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/poms/myproject.pom
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/jars/myproject.jar
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/srcs/myproject-sources.jar
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/docs/myproject-javadoc.jar
[info]  published ivy to /root/.ivy2/local/com.test/myproject/1.0.1/ivys/ivy.xml
[success] Total time: 77 s, completed May 7, 2019, 10:26:13 AM

and when i try to look the file contents of this container via

docker exec -t -i containerid /bin/bash

and look into

cd ///root/.ivy2

and ls -a only shows

.  ..  .sbt.ivy.lock  cache

the local folder is missing here but when i run the container it shows that it created the jar in /root/.ivy2/local/com.test/myproject/1.0.1/docs/myproject-javadoc.jar

why its not showing the local folder in .ivy2 folder what i am doing wrong here?

You are using docker wrongly in this case IMHO and I have a serious doubt that your docker exec command is targeting the correct container because, from what I see (and my very limited knowledge of sbt/scala), it should be dead by the time the jar is published. Let me explain.

sbt publishLocal is not a long living command. It will exit when the jar is published to the local .ivy store on disk. So when you launch a container from your image in foreground with docker run --name mytestcontainer myproject:v1 (I added a name for easier debugging purpose on your side...), I am pretty sure you see all your above logs and that the command exits back to your shell.

At this point, if you issue a docker ps, your mytestcontainer will not show up, unless with docker ps -awhere it will be listed in the exited container. If you try to start it again (docker start mytestcontainer), it will exit as soon as the jar is re-compiled/published. So there is no way to target an exec on this container since it is not running. The only way to have a shell in a running container out of this image is to override the start command in docker run but this will bypass your jar publication.

Now, what you first want is to publish the jar as part of the image, not to compile/publish it everytime you start a container out of the image.

FROM hseeberger/scala-sbt:11.0.2_2.12.8_1.2.8
MAINTAINER Sara Waheed <sarawaheed3191@gmail.com>

WORKDIR /myproject
ADD . /myproject

RUN sbt publishLocal

In this case, the jar will be published during the build

docker build -t myproject:v1

You can then run a container out of your image dropping to jshell as intended by the base image you are using:

docker run -it --rm --name testcontainer myproject:v1
May 12, 2019 8:31:33 AM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
|  Welcome to JShell -- Version 11.0.2
|  For an introduction type: /help intro

jshell>

Or if you want a more classic bash shell, you can override the start command:

docker run -it --rm --name testcontainer myproject:v1 /bin/bash

To go further, if your intent is to deliver your application in a ready to use image, you should have a look at Docker multistage builds. The idea is to build your jar in an image containing all the needed build tools and to copy the produced artifacts to an other image intended only for run that you will finally distribute. Here is the basic idea from your example. Image/command used are solely for illustration purpose and the process is highly perfectible (e.g. harcoded version....):

FROM hseeberger/scala-sbt:11.0.2_2.12.8_1.2.8 as build
WORKDIR /myproject
ADD . /myproject
RUN sbt publishLocal

FROM openjdk:8-alpine
WORKDIR /myproject
COPY --from=build /root/.ivy2/local/com.test/myproject/1.0.1/jars/myproject.jar .
CMD['java', '-jar', 'myproject.jar']


How to deploy a ZIP or WAR equivalent (built locally via npm)? I use NPM to build my web project, and it does so nicely to a little ZIP file. Keeps everything nice and light, and I can easily keep bloat down.

My current process is to use an FTP client (Win SCP), to upload the ZIP file, and then I have a little deploy.sh script that simply removes the old site, and unzips the new site to the same folder.

I want to be able to build this and deploy it all in one but cannot seem to find the answers. I'm not really sure where to start. I know I could move the build process to the server (git pull, and run the npm command there) but I would rather always have full visibility of the build locally before deployment (ie. could have one script to build, and another to deploy - so yes it technically is a manual deployment, but only manual in the sense that it is triggered).

If this is posted in the wrong place, please advise - any help greatly appreciated!

There are now two possible solutions: One NPM only one, and a clean one.

First the NPM One (where im not quite sure what exactly will work):

I just googled "npm deployment" and found 3 different Plugins which do exactly that what you want ( 1, 2, 3) and there are many more. Which now you suits you best, will be your choice.

Now the cleaner one (because we are in the DevOps Stackexchange ;) ):

Use a Dedicated Service (self-hosted or provided) to build and deploy your application.
This way you will just commit your sourcecode into the VCS and the build system will build your Artifact. Then you deploy it through there via it's possibility for it.

As Example i used Atlassian Bamboo quite often for that.

I commited my code
Bamboo gets a Trigger to build
Bamboo run the Build with the Tests
Bamboo create the Artifact
now you had the Choice to automatically deploy the Artifact or wait for a manuell Button press inside the UI

if automatically it will start a Deploy Task
else on Button Press

The Deploy Task is the configuration how it will be Deployed.

in your case: copy the ZIP, extract it, run the deployment.sh

One thing beside that all. One thing i would never do is to build ON the Live system. Sourcecode on the Live Server (even Javascript one, which is most of the time minified) is a big attack window. Beside that you could get many weird behavior due weird things that the different systems do inside the building of the artifact (like different dependencies or things like that)


How fast does Prometheus data grow? This may sound like a vague question so I will provide some context below. The basic question is :

What parameters describe the growth in size of a Prometheus database over time?

To tie the question down: When will the prometheus time series data base reach 1TB if I collect 10 metrics sampling them at 5 per minute?

Prometheus use a timeseries databases with vacuum, the documentation gives some maths to plan your disk consumption:

  On average, Prometheus uses only around 1-2 bytes per sample. Thus, to
  plan the capacity of a Prometheus server, you can use the rough
  formula:

needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample

So depending on your retention configuration, 1TB could never be reach or you can keep a very long time. That said it's using prometheus local storage, using another storage system will change the maths depending on the system concerned, influxdb is one of them and has its own documentation about storage.


Terraform: How to support releasing new versions of the code, running in parallel with the last stable release? I have one service in production (on AWS), which follows the immutable server pattern. Its deployment looks like this:

Create a new AMI with Packer
Create a new CloudFormation stack, starting with an auto-scaling group of size 1.

When I see that the new release is good, I can increase the number of instances and eventually shutdown old instances and finally remove the CloudFormation stack from the previous release.

In my initial version of the deployment, I used only one stack and updated it in place. For normal releases, that meant an the auto-scaling group was modified by CloudFormation to point to the new AMI. Then I had to either kill an existing instance or increase the auto scaling group to get an instance with the release running.

Using a new stack for every release makes the process simpler for me, as rollbacks are easier and it makes rolling out releases to parts of the users easier. Similar to the immutable server pattern, I avoid in-place updates but instead only create new resources (stacks in this case).

In the company that I work for, it is now more common to use Terraform instead of CloudFormation. I wonder if it is possible to adept the deployment that I sketched with Terraform. I don't mind using another tool, my main point is that I would like to preserve these basic concepts:

Allow deployments of new releases without touching the stable release
Instead of (in-place) updating the setup, only create new resources and kill the old resources.

So, far I have only briefly worked with Terraform and used it only to manage some small part for our infrastructure. As recommended, I kept the state in an S3 bucket, for instance:

# (from main.tf)
terraform {
  required_version = ">= 0.9.4"
  backend "s3" {
    bucket = "example-company-terraform-state"
    key    = "/foo-service/terraform.tfstate"
    region = "eu-central-1"
  }
}

Here, the key is always fixed. So, Terraform will update everything in place. I assume you could use a new key for new releases to have a similar effect as creating new CloudFormation stacks.

What I did not figure out is how to move traffic to the new instances. All instances should be behind an load balancer (ELB). I think, you could use a separated setup for the ELB, which will distribute traffic to instances from both the old and the new release.

So, if a new release is rolled out, there would be three different Terraform states:

Terraform setup for the ELB
Terraform setup for the old release (more specifically, its auto-scaling group)
Terraform setup for the new release

Questions:

Has the approach of using different S3 keys for the Terraform state the same effect as using separate CloudFormation stacks? (What I'm looking for is a way to have multiple Terraform setups that do not interfere with each other.)
Do you see a solution to the problem of getting all instances (from the old and the new release) behind a shared ELB?
I read that you can export resources in Terraform. Do you think, I could create a Terraform setup for the ELB, export the ELB as a resource, and use it in the Terraform setup for the instances (plus auto-scaling group) to make them attach to the shared ELB?

(Note: For my other service, where I use CloudFormation, we do not use an ELB, so it is strictly speaking a different problem. I only mentioned it to explain what I found useful about the deployment and why I think about applying some of the ideas for other services.)

There are a few different ways to achieve goals of this sort, each with some different tradeoffs. I'm going to describe the most common ones below.

The simplest approach is to use Terraform's create_before_destroy mechanism with autoscaling groups. An example of this pattern is included in the aws_launch_configuration documentation.

In this scenario, changing the AMI id causes the launch configuration to be re-created. Due to create_before_destroy, the new configuration is created first, then a new autoscaling group is created, adding the new instances to an attached ELB. The min_elb_capacity argument to aws_autoscaling_group can be used to ensure that a given number of instances are present and healthy in the attached ELB before considering the autoscaling group to be created, thus delaying the destruction of the old autoscaling group and launch configuration until the new one is serving requests.

The downside of this approach is the lack of control it represents. Since Terraform is thinking of the entire set of changes as a single run, it's impossible to pause after creating the new instances to allow other checks to be carried out before destroying the old ones. As a consequence, the ELB healthcheck is the only input to deciding if the new release is "good", and rolling back is impossible once the old resources have been destroyed.

A second common approach is to adopt a sort of "blue/green deployment" pattern with explicit changes to two clusters. This is done by putting all of the per-release resources in a child module, and instantiating that module twice with different arguments. In the top-level module this would look something like the following:

resource "aws_elb" "example" {
  instances = "${concat(module.blue.ec2_instance_ids, module.green.ec2_instance_ids)}"

  # ...
}

module "blue" {
  source = "./app"

  ami_id = "ami-1234"
  count  = 10
}

module "green" {
  source = "./app"

  ami_id = "ami-5678"
  count  = 0
}

The principle of operation here is that in the "steady state" (no deployment in progress) only one of these modules has a non-zero count, and the other one has zero. During a deployment, they are both set to the same non-zero count, but with different ami_id values. Each deployment swaps which of the modules is the "active" module, with both being active during the deployment.

When using this approach, each step is a distinct Terraform operation:

change count of the inactive module to nonzero and set its AMI id
apply the change with Terraform, thus activating the new module
verify that the new release is good
change count of the older module to zero
apply the change with Terraform, thus deactivating the old module

Although this has more steps, it allows arbitrary verification and an arbitrary amount of time to pass during step 3. It also allows "rolling back" by resetting the previously-inactive cluster count to zero.

Since both the old and new clusters exist in the same configuration, there is the risk of using this pattern incorrectly and prematurely destroying the active cluster. This can be mitigated by carefully reviewing Terraform's plan to make sure it leaves the old cluster untouched, but Terraform itself can't guarantee this.

Also, since both clusters are using the same child module configuration, it can be tricky to make updates to that configuration while retaining the blue/green separation. If changes are made that would require Terraform to replace the running instances, it's necessary to temporarily have two copies of the module code on disk, make the source arguments point to separate copies, and make the change only to the copy used by the inactive module.

The final approach I'll present is the most extreme and manual, but it does the best job of meeting your requirements and retaining control. This is, in effect, the most literal interpretation of your current CloudFormation workflow, and is a more concrete version of the approach you talked about in your question.

In this approach, there are two entirely-separate Terraform configurations, which I will call "version-agnostic" (things that must survive between versions, such as your ELB) and "version-specific" (the resources that are re-created for each new version).

The version-agnostic configuration will contain the ELB and will, as you suspected, export its id for consumption by the version-specific configuration:

terraform {
  required_version = ">= 0.9.4"
  backend "s3" {
    bucket = "example-company-terraform-state"
    key    = "exampleapp/version-agnostic"
    region = "eu-central-1"
  }
}

resource "aws_elb" "example" {
  # ...
}

output "elb_id" {
  value = "${aws_elb.example.id}"
}

This configuration can be initialized, planned and applied as usual, creating an ELB with no attached instances to start.

The version-specific configuration would be similar to the "app" child module in the previous approach, but this time as a top-level module. The backend configuration for this module would omit the S3 key, since this will change for each new release as you expected:

terraform {
  required_version = ">= 0.9.4"
  backend "s3" {
    bucket = "example-company-terraform-state"
    region = "eu-central-1"
  }
}

The specific key can then be set (or re-set) when running terraform init:

$ terraform init -reconfigure -backend-config="key=exampleapp/20170808-1"

Here I chose to use a "current date, release index" tuple as an identifier for a release. By running terraform init with a new value for this argument, an entirely separate state is created, independent of the last. Using -reconfigure tells Terraform that you don't wish to migrate the old state to the new, but rather to just switch directly to the new state path, possibly creating a new state in the process.

You can then run terraform show to confirm that indeed the state is empty (and thus operations won't affect existing resources) and then run a plan/apply cycle as normal.

Once you're satisfied with the new release, you can switch back to the previous version and destroy it.

The version-specific configuration will need the id of the ELB from the version-agnostic configuration in order to populate the load_balancers attribute of aws_autoscaling_group. To get access to this, we can use the terraform_remote_state data source to read the values from its state in S3:

data "terraform_remote_state" "version_agnostic" {
  backend = "s3"
  config {
    bucket = "example-company-terraform-state"
    key    = "exampleapp/version-agnostic"
    region = "eu-central-1"
  }
}

resource "aws_autoscaling_group" "example" {
  # ...

  load_balancers = ["${data.terraform_remote_state.version_agnostic.elb_id}"]
}

With a system of this complexity, it would likely be best to run Terraform via some sort of wrapper script or orchestration to make the release process less onerous. For example, such a script might automatically generate the new version number to avoid the risk of a human operator mistyping the date or accidentally conflicting with an existing one. There's some recommendations and caveats about running Terraform via scripts in the guide Running Terraform in Automation.

Although the third option here is the most direct mapping of your CloudFormation approach, the second option is more commonly used due to it striking a reasonable compromise between control and workflow overhead.


What is the behavior if docker compose fails? It seems to me that all the containers attempted to be launched are removed if Docker Compose fails for one container being launched.

Is this standard behavior, or is this just an artifact of my case?

Well it depends on whether the services (containers) within the docker-compose.yml depends on each other. If for example, service B depends on service A, and A fails to start up, so will B.

It can also be the case that a service logically depends on another service (without actually declaring it in your docker-compose.yml), and it not starting up causes a chain of failures. For example, say you have a web service and a db service. If the web service attempts to connect to the db service but the db service couldn't start up (config broken for example), then the web service will probably throw an exception and fail.

But no, just because one service fails, doesn't mean all other services will just be stopped. You can have two independent services, where one fails and stops, while the other is still running.


Reusable module in Terraform I want to get an autoscaling group name variable in module_apps and use it in other modules - for example module_init. However when I try to run terraform plan it does not work.

content of module_apps

resource "aws_autoscaling_group" "example"
{
  name = "asg-ad"
}

output "asg_name"
{
  value = "${aws_autoscaling_group.example.name}"
}

content of module_init

module "module_init"
{
  source = "../module_apps"
  asg_name = "${module.module_init.asg_name}"
}

Trying to run terraform plan seems that it can't get the source module:

o:Get: file:///home/user/terraform/application/module_apps
o:Get: file:///home/user//terraform/application/module_init
o:Get: file:///home/user//terraform/application/module_elb
o:Get: file:///home/user//terraform/application/module_deloy
o:Get: file:///home/user/terraform/application/module_apps
o:Get: file:///home/user//terraform/application/module_init
o:Get: file:///home/user//terraform/application/module_elb
o:Get: file:///home/user//terraform/application/module_deloy
o:Get: file:///home/user//terraform/application/module_init
o:Get: file:///home/user//terraform/application/module_elb
o:Get: file:///home/user//terraform/application/module_deloy
o:Get: file:///home/user/terraform/application/module_apps
o:Get: file:///home/user//terraform/application/module_init
o:Get: file:///home/user//terraform/application/module_elb
o:Get: file:///home/user//terraform/application/module_deloy
o:Get: file:///home/user//terraform/application/module_init
o:Get: file:///home/user//terraform/application/module_elb
o:Get: file:///home/user//terraform/application/module_deloy
o:Get: file:///home/user/terraform/application/module_apps
o:Get: file:///home/user//terraform/application/module_init
o:Get: file:///home/user//terraform/application/module_elb
o:Get: file:///home/user//terraform/application/module_deloy

If it doesn't outright fail you can expect to see a cycle warning where you've created a loop in Terraform and it's trying to fulfil your request for asg-name before the asg has been created.

To get what you need you'll need to have something like the following:

module_apps/module_apps.tf

resource "aws_autoscaling_group" "example" {
  name = "${var.asg_name}"
}

module_init.tf

variable "asg_name" { default = "asg-ad" }

module "module_init" {
  source = "../module_apps"

  asg_name = "${var.asg_name}"
}

output "asg_name" {
  value = "${var.asg_name}"
}

This way, if you call module_init somewhere else you'll have asg_name available to you. Always be careful of trying to use an output of a module to create the module, Terraform doesn't handle loops like that well and the errors can be confusing to diagnose.


What are the pros and cons of Azure Artifacts vs. Artifactory? We have a requirement where we need to develop a custom product where the software component life cycle needs to be managed i.e. upload, download, recall etc. one option is to go with Custom API leveraging Azure Artifacts and the other option is to go with Artifactory.
Can we have some insight on what are the Pros and Cons of these two solution.
some of the links which provides info are
https://www.g2.com/products/azure-artifacts/competitors/alternatives
In addition to that i would also like to understand how is their support towards package managers mainly cocoapods, maven etc

JFrog Artifactory pros

Artifactory supports 25+ package types, while Azure supports only Maven, npm, NuGet and Python. You can get Docker and Helm with Azure Container Registry but it’s a separate tool.

Artifactory is fully hybrid - available both for on-premise installations and as SaaS - with full parity between the versions.

With Artifactory you can avoid vendor lock-in - not depending just on one cloud vendor for all of your needs. That also means not being limited to any vendor’s stack for your database, access management, etc.
 Proxy any remote repository - not just the official ones (like Maven Central and PyPI.org)

Artifactory is optimized for multi-site operations - Supports any network topology, over multiple, geographically distant sites and data centers, through different options for replication including pull, push, event-based and multi-push replication.

Rich metadata & AQL - Artifactory provides full metadata capabilities for all major package formats for both artifacts and folders – including custom metadata. Users can tag artifacts and folders with searchable properties. Artifactory also collects build information for build artifacts as part of the CI server integration (see below). AQL gives you unprecedented flexibility in how you search for artifacts. It offers a simple way to formulate complex queries that specify any number of search criteria, filters, sorting options and output fields.

Build info - Artifactory stores exhaustive metadata for all build artifacts deployed to it. With this “bill of materials” it is easy to faithfully reproduce a build, and trace the cause of issues to reduce time to resolution (TTR), even if the build is already in production.

Azure Artifacts pros

if your CI is already built on Azure DevOps, the initial set up for Azure Artifacts may be a bit quicker. The basic functionality of hosting artifacts, so that they can be resolved by other builds will work for you.

Disclaimer: I'm a JFrog employee.


Is icmp blocked at travis-ci? I have a

ping -c 1 -q n.n.n.n command

that fails only at Travis CI.

Is ping blocked there?

Found the answer to my own question, straight from travis support

  Hi Name,

  Thanks for writing in. Yes indeed, on our container based
  infrastructure, ICMP is not possible. Could you speficy sudo:
  required in the .travis.yml and see if it brings improvement?

  Thanks!

  Joep


Which plugin should I use to get started with Jenkins to manage mainframe components in PDS format? Assume somebody familiar with DevOps and mainframes, but new to Jenkins, wants to get started with Jenkins, e.g. to:

investigate the feasibility of managing data stored in personal files (PDSes, i.e. partitioned data sets) on the mainframe (so not, yet, managed by any of the typical SCM solutions exist for managing mainframe software).
to run Jenkins in some type of personal development environment, e.g. in a Linux environment in Virtual Box (if that would make sense).

After some kind of (minimal) Jenkins installation and configuration got completed, the actual question becomes "Which of the typical Jenkins plugins, if any, would be needed?". From the various Jenkins plugins that appear to make sense in my case, it seems that these are possible candidates (quotes are from the linked pages):

IBM zOS Connector.

... provides its functions via FTP connection to IBM z/OS LPAR. You can configure your SCLM project on z/OS and then check for the changes via Jenkins.
Features include:

Submission of user JCL job (with optional log collected upon finish).
Introduction of SCLM as SCM for your projects allowing to checkout SCLM changes.
The ability to build SCLM projects currently can be performed only via 'Submit zOS Job' build action.

Compuware Source Code Download for Endevor, PDS, and ISPW Plugin.

... allows Jenkins users to download Endevor, PDS, or ISPW members from the mainframe to the PC. Source can then be accessed on the PC, for example, for SonarQube analysis and reporting.

Since the 1st plugin is about SCLM (which is all about PDSes), and the 2nd plugin explicitly states support for PDSes (in its name), I trust both are possible candidates.
So assuming my shortlist is complete (is it?), what are the pros and cons of either one that should help me decide which one is best for my case?
Ps: Something like a "Jenkins Kickstart" package doesn't seem to exist (at least I've not found it yet).

I set up jenkins to manage mainframe tables.   Essentially utilizing groovy script plugin. I wrote code that handles movement of files on the mainframe and call them though the plugin.   Essentially leveraging the mainframes API to connect and the vsc's commands to move the files.


How to create a MariaDB/MySQL image using utf8 instead of the default latin1 charset? I noticed when running a stock MariaDB Docker image in a container, the default character set is latin1:

CID=$(sudo docker run -d --rm -e MYSQL_ROOT_PASSWORD=p mariadb:10.3)
echo "show variables like 'char%';" | sudo docker exec -i "$CID" mysql -t -u root -pp
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

I suspect(correct me if I'm wrong) this may be related to the container's system locale :

echo "locale" | sudo docker exec -i "$CID" bash
[sudo] password for sylvain:
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

Is there a way to create a MariaDB image using utf8 everywhere without having to write and mount a custom my.cnf configuration file? Ideally, I'm looking for a Dockerfile-based solution.

In the official MariaDB image, my.cnf is configured to read additional configuration files from the /etc/mysql/conf.d/ and /etc/mysql/maria.conf.d/ directories:

root@bbd24e22be98:/# tail /etc/mysql/my.cnf

#
# * IMPORTANT: Additional settings that can override those from this file!
#   The files must end with '.cnf', otherwise they'll be ignored.
#
!include /etc/mysql/mariadb.cnf
!includedir /etc/mysql/conf.d/

root@bbd24e22be98:/# tail /etc/mysql/mariadb.cnf
# * Character sets
#
# Default is Latin1, if you need UTF-8 set all this (also in client section)
#
#character_set_server   = utf8
#collation_server       = utf8_general_ci
# Import all .cnf files from configuration directory
!includedir /etc/mysql/mariadb.conf.d/

Based on that, it is quite easy to setup utf8 everywhere by writing a configuration file to override the relevant settings, copying it at the right place from your Dockerfile:

$ cat db/utf8.cnf
[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake

$ cat db/Dockerfile
# Base image
FROM mariadb:10.4

# utf8 everywhere
COPY utf8.cnf /etc/mysql/mariadb.conf.d/
ENV MYSQL_RANDOM_ROOT_PASSWORD=yes

I let you compare the output of show variables after those changes with the one provided in the question:

MariaDB [(none)]> show variables like 'char%'
    -> ;
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+


Built codebase doesnt appear after deploying I'm packaging and shipping a custom code base of Wordpress with a Dockerfile in to my private container registry.
Dockerfile:
FROM wordpress:latest
ADD . /var/www/html

Then on the deployment server I just use docker-compose.yml and grab my custom image.
and also I'm mounting this needed directory to host.
docker-compose.yml
volumes:
  - .:/var/www/html

Container starts and runs without any hustle. However the problem is the code (files, directories) I ported earlier doesn't show on the deployment. Only the official wordpress:latest data are there.
What I'm missing here?

Another try
Then I tried something like this. Instead of directly ADD . /var/www/html/, I copied code base to another directory ADD . /app on build and on the deployment docker-compose.yml, I tried to cp -a /app/. /var/www/html with a command parameter. Command and cp works. However it happens before wordpress:latest script runs and it avoid coping official wordpress files, which I don't want. I expect some official files from wordpress:latest to be copied to the /var/www/html/ then my customer data to be copied from /app
Whats the missing ingredient here?
However in that case

Well after some research, it seems the initial issue was caused by the volume mount configuration in the host's docker-compose.yml

Even I put below line on build Dockerfile which copies the files to the given path

ADD . /var/www/html

Since the host's docker-compose.yml got line like below

volumes:
    - .:/var/www/html

The container mounting this directory as a new directory to it's Unix like filesystem. So it masks the underlying files.
So on the file system its a new directory and doesn't represent the underlying files. Basically its empty.
This Github issue confirms this.

Then it runs the wordpress:latest's docker-entrypoint.sh
Which set /var/www/html as the working directory and if it doesn't contain index.php and wp-includes/version.php (obviously it doesn't due to above matter, directory is new) inside, it downloads and extract WordPress source to this directory. That's why after the mount, my old bundled data wasn't there.

So I was basically tried to do something which was not intended.

As @Jeremy commented,

  as /var/www/html? It sounds like your mount is failing - and that the
  ADD Is superfluous

Another try Was totally wrong. Because I was adding a custom ENTRYPOINT script to my build Dockerfile, so it keeps ignoring the base image wordpress's ENTRYPOINT and CMD that's why it wasn't copy new source to the directory.


How to run a CMD in a docker container that was created using Packer? So I am creating a docker image with packer.
The template defines the provisioners and builders etc.
The builder section looks like this:

{
    "builders": [
        {
            "type": "docker",
            "image": "ubuntu:latest",
            "export_path": "image.tar",
            "changes": [
                "USER test",
                "WORKDIR /tmp",
                "VOLUME /data",
                "EXPOSE 21 22",
                "CMD sudo myprogram"
            ]
        }
    ]
}

When running packer against the template, the output is an image.tar file.
I can then import it: docker import image.tar.
And then I start like this docker run -p 21:21 -it --rm 52c0b0362362 bash.

I want whenever the image is started that automatically sudo myprogram is executed. However it does not seem to work, even tho the template validated successfully. I also tried instead of specifying CMD sudo myprogram to set it as entrypoint like so: ENTRYPOINT sudo myprogram.
Neither worked. How can I make sure whenever my image is started, this command is automatically executed? It must be run as root/with sudo, that's important.

And then I start like this docker run -p 21:21 -it --rm 52c0b0362362 bash

This would not work by design. When you run the image with the command above you are instructing Docker to overwrite the CMD instruction from your Dockerfile and therefore telling it to execute bash instead of sudo myprogram. It doesn't matter what you have set in the CMD instruction - it would never be executed.

One way you could go around this would be to use ENTRYPOINT as others have suggested. This will make sudo myprogram the default command and then CMD can act as "additional arguments" to the default command (sudo myprogram).

Here's a working example:

# build.json
{
    "builders": [
        {
            "type": "docker",
            "image": "ubuntu:latest",
            "commit": true,
            "changes": [
                "ONBUILD RUN apt-get -q update",
                "ONBUILD RUN apt-get install -y -q htop",
                "ENTRYPOINT [\"top\"]"
            ]
        }
    ]
}

# /packer build ./build.json

# run top with delay 3 sec
# docker run --rm -it sha256:hash

# run top with delay 1 sec
# docker run --rm -it sha256:hash -d 1

The other solution would be to keep the CMD [\"sudo myprogram\"] instruction but to run the image without adding a command at the end: docker run -it --rm HASH_ID.


Why `docker diff` does not see some file changes? I know when you create a container the Docker engine adds a thin writable layer on top of the image layers. And all filesystem changes are recorded in that writable layer.

I know I can use the docker diff command to show the changes made in a container's filesystem compared to the base image.

But surprisingly, I cannot see where data are saved in the following use case involving the official MongoDB image:

sh$ sudo docker run -d --name mongo mongo:3.6.10
sh$ sudo docker exec -i mongo mongo << EOF
> db.test.insert({foo:"bar"})
> EOF
MongoDB shell version v3.6.10
MongoDB server version: 3.6.10
WriteResult({ "nInserted" : 1 })
bye

sh$ sudo docker stop mongo
sh$ sudo docker diff mongo
C /root
A /root/.dbshell
C /tmp

/tmp is empty. And /root/.dbshell is just the history file for the mongo client. But I can't see any trace of the data files modified by the Mongo DB server. However, data were definitely stored:

sh$ sudo docker start mongo
sh$ sudo docker exec -i mongo mongo << EOF
> db.test.find()
> EOF
MongoDB shell version v3.6.10
MongoDB server version: 3.6.10
{ "_id" : ObjectId("5c750d4cef8f9635fe459f06"), "foo" : "bar" }
bye

And I can find the data when I manually dump the files:

sh$ sudo docker exec mongo bash -c 'tar c /data/db/collection*' | hexdump -C | grep foo
tar: Removing leading `/' from member names
0000e840  02 66 6f 6f 00 04 00 00  00 62 61 72 00 00 00 00  |.foo.....bar....|

Why can't I find the data files modified by the MongoDB server using docker diff? Did I make some wrong assumption somewhere? Or did I misunderstood something regarding the way docker diff works?

I don't know how I missed that, but the mongo image by default stores data in a Docker managed volume, and not in the container writable layer as I assumed it initially.


Are there arguments against using “imagization" tools in the literature and if so, what are the main ones? Although I never used an "imagization" tool (for example, Docker) I understand a container as an instantiated (running or stopped) image which in plural are simply put, a server environment and corresponding application/s, cloned from one computerized machine into another computerized machine (likely a virtual machine);
I further understand such cloning operations save time because application/s (and maybe also an OS) shouldn't be installed again and configured again to reach the state of the cloned machine, so one could start from the cloned state and make changes from there.

My problem

When I still used Facebook, I spoke there with some anonymous sysadmin who claimed something like he doesn't use imagization tools as an image could be contaminated with malicious software or hacked somewhere along the process without him knowing it.

I am not sure I enough understand what "imagization" tools are and the subsequent opinion I presented.

My question

Are there arguments against using “imagization" tools in the literature and if so, what are the main ones?

You might have better luck finding answers to your questions if you use the more standard term of "containerization".

This article discusses containerization as well as some pros and cons you might want to consider.


How are ansible playbooks supposed to be imported into a collection? I'm trying to develop a reusable collection of playbooks that I can run from docker containers.  I don't want to share duplicate code between containers and I don't want to have containers that run multiple playbooks so what I'd like do develop is something where I have a
playbooks/doit.yml
file and a
.ansible/collections/playbooks/x/y/playbooks/thing-to-do.yml
playbook that I can import into my playbook
However, none of the documentation explains how to do that yet.
import playbooks doesn't say anything about collections
https://docs.ansible.com/ansible/latest/modules/import_playbook_module.html
and playbooks collection documentation currently says tbd
https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html#playbooks-directory
I'm running ansible 2.9, I suppose I could import the playbook given the full path, but that seems like not what they're wanting me to do.

this feature was recently merged to ansible devel branch. It would be posible using:
- import_playbook: testns.testcoll.default_collection_playbook


Consul cluster does not work as expected when one of server is down I guess, the main purpose of a cluster is failure tolerance. However, when I start the following consul cluster, in docker, it is not the case and I don't understand why.

services:

  # docker network create --driver=bridge discovery-network

  # SERVICE DISCOVERY
  consul-server-0:
    image: consul:1.6.0
    container_name: consul-server-0
    command: "agent -server -bootstrap-expect 2 -client 0.0.0.0 -datacenter datacenter-1 -node consul-server-0"
    networks:
      - discovery-network

  consul-server-1:
    image: consul:1.6.0
    container_name: consul-server-1
    command: "agent -server -retry-join consul-server-0 -client 0.0.0.0 -datacenter datacenter-1  -node consul-server-1"
    networks:
      - discovery-network
    depends_on:
      - consul-server-0

  consul-client-1:
    image: consul:1.6.0
    container_name: consul-client-1
    command: "agent -retry-join consul-server-0 -ui -client 0.0.0.0  -datacenter datacenter-1  -node consul-client-1"
    ports:
      - "8500:8500" # GUI
    networks:
      - discovery-network
    depends_on:
      - consul-server-0

networks:
  discovery-network:
    external:true

When I stop one of servers, the cluster does not work anymore. I am unable to register anymore service (through consul-client).

In the remaining server's logs, I can see the message Failed to make RequestVote RPC
In the client's logs, I can see the message No cluster leader

What is wrong with my configuration?

Based on my understanding of the topology you have described you essential have:

3 Nodes - 2 Servers and 1 Client

This layout is immediately a problem because the clustering protocol that consul uses relys on being able to easily elect a leader, which requires an odd number of servers.

If you consider the failure scenario of a 2 node consul cluster - as soon as a single node goes down your one remaining node cannot achieve consensus by itself because there's no way to get a majority of the servers voting on something.

In the consul docs the consensus protocol is reasonably well described Consensus docs

They even include a summary table which explicitly states how many server members could be lost for varying cluster sizes.

Following their advice, your 2 server cluster cannot withstand any fault because it would then become impossible to achieve quorum.

Really a minimum number of servers for a functional consul cluster is 3.


What artifact managers are available in GCP? I use artifactory and nexus, but I wonder what artifact manager could be used in GCP? Is there a managed artifact manager or do I have to run one myself in a VM?

If the artifacts in question are docker images then the recommended artifact management solution is the Container Registry, well integrated with other GCP products producing and/or using such images.

AFAIK they don't have a real artifact manager for other kinds of artifacts, they suggest the rather general purpose Cloud Storage for that. You can find an example of such use in the Quickstart for Go guide. Most likely not what you're looking for:

artifacts:
  objects:
    location: 'gs://[BUCKET_NAME]/'
    paths: ['hello']


How can I automatically post Codefresh build results to pull requests in Bitbucket? I have a BitBucket Cloud repository with a WebHook to trigger Codefresh builds on Pull Requests.  I would like the build results to appear as comments on the PRs, similar to the way Travis integration works for GitHub.

I couldn't find any settings for this in my BitBucket repository or in Codefresh, but Codefresh's documentation seems to suggest that this happens automatically when you setup integration with GitHub.

I can't find any examples of BitBucket repository with automatic comments. Is it supported?

One could update the build status in bitbucket as follows:

  Adding a build result to a commit

  To associate a build result with a particular commit, you need to POST
  a JSON object to the build status REST resource at:

  https://<bitbucket-base-url>/rest/build-status/1.0/commits/<commit-hash>

  The format of the JSON object that should be used as the request body
  is:

{
    "state": "<INPROGRESS|SUCCESSFUL|FAILED>",
    "key": "<build-key>",
    "name": "<build-name>",
    "url": "<build-url>",
    "description": "<build-description>"
}

One could run such a snippet by codefresh at the end of the build using a script to notify bitbucket regarding the build status of a commit.

  One green build

  The following curl command will add a build to the commit
  9e72f04322c4a1f240e0b3158c67c3c19cdd16e7:

curl -u username:password -H "Content-Type: application/json" -X POST
http://localhost:7990/bitbucket/rest/build-status/1.0/commits/9e72f04322c4a1f240e0b3158c67c3c19cdd16e7
-d @build0.json

  Where build0.json contains:

{
    "state": "SUCCESSFUL",
    "key": "REPO-MASTER",
    "name": "REPO-MASTER-42",
    "url": "https://bamboo.example.com/browse/REPO-MASTER-42",
    "description": "Changes by John Doe"
}


What is the most common server permission policy for web application deployment? I have a server with Ubuntu with a web server (Apache or Nginx) running a PHP application. The application consists of the following parts:

An executable code that handles HTTP requests (say in the /var/www/demoapp/app directory)
A configuration (say the /var/www/demoapp/.env file)
A file storage where the application puts its data (caches, uploads, etc; say in the /var/www/demoapp/storage directory). The application writes files behalf the web server user with 644 mode (let's say I can't make the application write with another mode).

A deployment of the PHP application is made via SSH (the server is connected to) and consists of two stages:

Upload the executable code to the server
Run migrations. The migrations must be able to write the configuration file and the file storage. Running migrations means executing a shell command (e.g. cd /var/www/demoapp/app && ./migrate.php).

What is the proper or the most common strategy of user/group accesses and file permissions for such application and deployment process? I expect an answer like «the web server should be run behalf user1, the SSH should be accessed via user2, the /var/www/demoapp directory should have the xxx mode and so on».

Due to security concerns, I don't want the SSH deployment user to be able to run commands behalf root. And I don't want the web application to be able to write the executable and the configuration files (except when there is a migration running). I admit these requirements may be omitted keeping a good security level.

According to the Nginx docs you can configure the user which runs Nginx. By default the user is nobody.

You can read this Ask Ubuntu question that explains how to configure Apache2 to run as a different user. The default user running Apache2 is www-data.

A common strategy, and one I think may work for your goal, is to assign the users that need to deploy the application to a common group. For instance, if you added them to the www-data group:

sudo adduser <user> www-data

You can see which groups is a member of with:

groups <user>

Then change the group of the directory where users will run migrate.php:

sudo chgrp -R www-data /var/www/demoapp

Then assign the group read/write/execute permissions to the directory:

sudo chmod -R g+rwx /var/www/demoapp/

The users in this group should now be able to write and run scripts within the demoapp/ directory.


In ansible how to select specific tasks in a role according to the playbook or a more general parameter? My understanding of Ansible roles is that they are the unit of reusability when implementing processes using Ansible, similarly to what a class or a package is in some computer languages.

It therefore seems natural to use roles to make all tasks understanding a given data structure in a specific role, but this yields the question of how to select the actual tasks to perform?  Is it a good design to use the main.yml file in the task as an entrypoint to select actual tasks according to role parameters?

For instance a framework role could feature:

a defaults/main.yml file that understands the framework variable that could be define by a vars file shared by all playbooks in a project like

framework:
  java: [tomcat, mysql]
  php: yes

so that after processing the defaults/main.yml file the following variables:

framework__enable_java_core: yes
framework__enable_java_tomcat: yes
framework__enable_java_mysql: yes
framework__enable_php_core: yes

are defined and can be used by the role to actually know which tasks to perform.

several tasks like java.yml, php.yml pro framework, which select actions to perform according to a when: action == 'WHATEVER-ACTION is to perform; the main.yml then leek all the corresponding tasks.
playbooks that say

for instance

roles:
- { role: framework, action: apt-setup }

or

roles:
- { role: framework, action: install }

or

roles:
- { role: framework, action: uninstall }

This kind of approaches turns out to scale very well when working with Makefiles.  It is therefore tempting to use it again when writing complex ansible systems.  On the one hand, it seems to fit quite naturally in the language used by ansible. On the other hand, it generates quite a payload of “skipped” tasks in ansible logs, which raises a red sign to me.

Is the approach I describe a sensible way to group data structures with the processes using it? (That is, to implement reutilisation!)  If not, what would be a better way?

Different approaches can be useful for different setups. You can use tags in some cases, or conditional includes (as you describe) in other cases.

  On the other hand, it generates quite a payload of “skipped” tasks in ansible logs, which raises a red sign to me.

You should get familiar with difference between static and dynamic includes in Ansible.

So if you use static includes, you will get a lot of skipped tasks, because every task in every file is added to execution queue but most of them are skipped because of when statement.

tasks/main.yml of your role with actions install/uninstall:

- include: install.yml
  when: action == 'install'
- include: uninstall.yml
  when: action == 'uninstall'

But if you use dynamic includes, only required tasks are added to execution queue and skipped message is displayed for skipped includes.

tasks/main.yml:

- include_tasks: install.yml
  when: action == 'install'
- include_tasks: uninstall.yml
  when: action == 'uninstall'

More on that, you can avoid skipped message altogether like this:

tasks/main.yml:

- include_tasks: '{{ action }}.yml'

The drawback of dynamic includes is that you can't do complete static analysis of your playbook (like syntax checks, etc.) because many things are know only in runtime.


How to route to specific, of multiple datacenters, with a single domain The data of each customer only exist in one of several global datacenters, that all answer to the same hostname (ex. api.company.com)

Only a single domain for all customers globally
I want to make sure that all global customers only have to use a single domain: api.company.com to access their data, and not something like api-region3.company.com, but it may not be possible.

GEO Location DNS may go to wrong datacenter
I cannot use geo-location DNS directly, because that would mean that someone might end up accessing a datacenter that does not contain the data for that customer.

Possible solution
I could use a proxy at each of the datacenters to relay the request to the correct datacenter, based on some information in the request, but I'm not sure if there's some better established industry standard way of doing this, without duplicating the data across all datacenters. In case proxying/relaying is the best option, what is some tried-and-tested options for actually setting this up?

Proxying is gonna cause you some issues when someone takes a trip to China and tries to access data in the USA, depending on what your app does they could cause you some $$$ issues when your Chinese POP is sending/receiving all of their traffic each way.

Instead I suggest:

If your API is authenticated and you're not going to replicate any of the data and you're using AWS then I'd use lambda@edge to do what you need.

You can use GEO-DNS to route to a lambda function which handles authentication. This lambda function can also hold a record of where users need to go and issue a redirect to the correct endpoint.

This does mean that you'll still need domains like api-region3.company.com but it will allow api.company.com to perform the task of being universal. It's down to the client application then to hold on to that URL? At least using redirects instead of proxies should help with network traffic.


Vagrantfile change with Ansible playbook to control file permission on Vagrant synced folder for Trellis I use Trellis for my WordPress development. It works great, except I'm finding it hard to change file (or directory) permission within the synced folder.

Generally I'm OK with the default permission setup. However, sometimes I need to give write permission to some of the sub-directories of the main (NFS) synced directory.

This is the Vagrantfile that uses Ansible playbook for the main configuration of the VM (I use VirtualBox). I'm not a Ruby programmer nor have I worked with Ansible, however, by the looks of it, the following is the part of the Vagrantfile where file permissions are being set:

if Vagrant::Util::Platform.windows? and !Vagrant.has_plugin? 'vagrant-winnfsd'
    wordpress_sites.each_pair do |name, site|
        config.vm.synced_folder local_site_path(site), remote_site_path(name, site), owner: 'vagrant', group: 'www-data', mount_options: ['dmode=776', 'fmode=775']
    end
    config.vm.synced_folder ANSIBLE_PATH, ANSIBLE_PATH_ON_VM, mount_options: ['dmode=755', 'fmode=644']
    config.vm.synced_folder File.join(ANSIBLE_PATH, 'bin'), bin_path, mount_options: ['dmode=755', 'fmode=755']
else
    if !Vagrant.has_plugin? 'vagrant-bindfs'
        fail_with_message "vagrant-bindfs missing, please install the plugin with this command:\nvagrant plugin install vagrant-bindfs"
    else
        wordpress_sites.each_pair do |name, site|
            config.vm.synced_folder local_site_path(site), nfs_path(name), type: 'nfs'
            config.bindfs.bind_folder nfs_path(name), remote_site_path(name, site), u: 'vagrant', g: 'www-data', o: 'nonempty'
        end
        config.vm.synced_folder ANSIBLE_PATH, '/ansible-nfs', type: 'nfs'
        config.bindfs.bind_folder '/ansible-nfs', ANSIBLE_PATH_ON_VM, o: 'nonempty', p: '0644,a+D'
        config.bindfs.bind_folder bin_path, bin_path, perms: '0755'
    end
end

How can I make changes to this file in a way so that I can control permission to specific files and folders when I need. Since changing the permission within the vagrant synced folder on the host machine doesn't reflect on the Virtual Machine, I must at least be able to do it by changing the Vagrantfile and then re-provisioning.

How can I achieve this easily that will persist upon future re-provisioning?

There are two parts of this Vagrantfile, one does the mounting for Windows hosts (the first half), the other one for UNIX hosts (the second half), but essentially the do the same - just with different plugins.

You can see from the config.vm.synced_folder and config.bindfs.bind_folder commands where they set up the appropriate directories with the proper permissions.

To add a new directory with different permissions simply add them to the list. Note that File.join('a','b') simply converts the path to a/b, but it's a nicer way to do it, as it's platform independent (on Windows it can also handle \ style paths).

So for example if you want to give the /tmp/needswrite folder more permission you can simply add the following two lines to their appropriate places:

Windows config:

config.vm.synced_folder File.join(ANSIBLE_PATH, 'tmp', 'needswrite'), File.join(ANSIBLE_PATH_ON_VM, 'tmp', 'needswrite'), mount_options: ['dmode=777', 'fmode=777']

Unix config:

config.bindfs.bind_folder File.join(ANSIBLE_PATH_ON_VM, 'tmp', 'needswrite'), File.join(ANSIBLE_PATH_ON_VM, 'tmp', 'needswrite'), perms: '0777'

This will for example set their permission to 777 instead of the default 755

Note that in the Windows config you have to map from ANSIBLE_PATH to ANSIBLE_PATH_ON_VM, while on the Unix config bindfs will do a remount, so you need to match them with the same directory name.

You can also play with users and groups:

Windows config:

config.vm.synced_folder File.join(ANSIBLE_PATH, 'tmp', 'needswrite'), File.join(ANSIBLE_PATH_ON_VM, 'tmp', 'needswrite'), owner: 'new-owner', group: 'new-group', mount_options: ['dmode=755', 'fmode=755']

Unix config:

config.bindfs.bind_folder File.join(ANSIBLE_PATH_ON_VM, 'tmp', 'needswrite'), File.join(ANSIBLE_PATH_ON_VM, 'tmp', 'needswrite'), u: 'new-owner', g: 'new-group', perms: '0777'

Here we set them to use user new-owner and group new-group


How to Configure jenkins email notification for some commercial email services? For configuring jenkins email notification with some corporate email server or commercial email services.

How we can get mail server setting details like mail server name, port number, using SSL, etc. for such email services?

You may consider these two Jenkins plugins for it:

https://wiki.jenkins.io/display/JENKINS/Mailer

https://wiki.jenkins.io/display/JENKINS/Email-ext+plugin

The first one is mostly basic and the second one is extended for additional user customizations. All necessary instructions regarding configuration, etc are described there.

      How we can get mail server setting details like mail server name, port number, using SSL, etc. for such email services?

I am afraid that the best approach here is either refer to your system administrator who is resposible for it or contact with the provider who provides mail services.