Posted in Information Technology

Process Collections Easily With Stream in Java 8

In Java, collections and arrays are two common data structures, on which many operations are regularly performed, including addition, deletion, modification, query, aggregate, statistics, and filtering. These operations also exist in relational databases. However, it is not very convenient to process collections and arrays before Java 8.

This problem is greatly alleviated in Java 8 by introducing a new abstraction called Stream API, which allows us to process data in a declarative manner. This article shows how to use Stream. Note that the performance and principles of Stream are not the central part of this article.

Stream Introduction

Stream provides a high-level abstraction for Java collection operations and expressions by querying data from databases similar to SQL statements.

Stream API can significantly improve the productivity of Java programmers and allow them write effective, clean, and concise code.

A collection of elements to be processed are considered as a stream, which is transmitted in a pipeline. These elements can be processed on nodes of the pipeline, such as filter, sort, and aggregate.

Characteristics and Advantages of Java Streams:

  • No storage. A Stream is not a data structure, but only a view of a data source, which can be an array, a Java container or an I/O channel.
  • A Stream is functional in nature. Any modifications to a Stream will not change the data sources. For example, filtering a Stream does not delete filtered elements, but generates a new Stream that does not contain filtered elements.
  • Lazy execution. Operations on a Stream will not be executed immediately. They will be executed only when users really need results.
  • Consumable. The elements of a stream are only visited once during the life of a stream. Once traversed, a Stream is invalidated, just like a container iterator. You have to regenerate a new Stream if you want to traverse the Stream again.

Let’s use an example to see what a Stream can do:

Image title

The preceding example gets some plastic balls as the data source, filters the red ones, melts them down and converts them into random triangles. Another filter removes small triangles. A reducer sums up the circumferences

As shown in the preceding figure, a Stream involves three critical operations: stream creation, intermediate operations and terminal operations.

Stream Creation

In Java 8, many methods can be used to create a Stream.

1. Create a Stream by Using Existing Collections

In addition to many stream-related classes, Java 8 also enhances the collection class itself. The stream method in Java 8 can convert a collection into a Stream.

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");
Stream<String> stream = strings.stream();

The preceding example creates a Stream from an existing List. In addition, the parallelStream method can create a parallel stream for a collection.

It is also very common to create a Stream from a collection.

2. Create a Stream by Using the Stream Method

The of method provided by Stream can be used to directly return a Stream consisting of specified elements.

Stream<String> stream = Stream.of("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");

The preceding code creates and returns a Stream by using the of method.

Stream Intermediate Operations

A Stream may have many intermediate operations, which can be combined to form a pipeline. Each intermediate operation is like a worker on the pipeline. Each worker can process the Stream. intermediate operations return a new Stream.

Image title

The following is a list of common intermediate operations:

Image title

filter

The filter method is used to filter elements by specified conditions. The following code snippet uses the filter method to filter empty strings:

List<String> strings = Arrays.asList("Hollis", "", "HollisChuang", "H", "hollis");
strings.stream().filter(string -> ! string.isEmpty()).forEach(System.out::println);
//Hollis, , HollisChuang, H, hollis

map

The map method maps each elements to its corresponding result. The following code snippet use the map method to generate the square numbers of corresponding elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().map( i -> i*i).forEach(System.out::println);
//9,4,4,9,49,9,25

limit/skip

Limit returns the first N elements in a Stream. Skip abandons the first N elements in a Stream. The following code snippet uses the limit method to retain the first four elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().limit(4).forEach(System.out::println);
//3,2,2,3

sorted

The sorted method sorts elements in a Stream. The following code snippet uses the sorted method to sort Stream elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().sorted().forEach(System.out::println);
//2,2,3,3,3,5,7

distinct

The distinct method is used to remove duplicates. The following code snippet uses the distinct method to deduplicate elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().distinct().forEach(System.out::println);
//3,2,7,5

Next, we use an example and a figure to show what will happen to a Stream after performing operations filter, map, sort, limit, and distinct.

The following is the code:

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");
Stream s = strings.stream().filter(string -> string.length()<= 6).map(String::length).sorted().limit(3)
            .distinct();

The following figure shows steps and the result for each step.

Image title

Stream Terminal Operations

Stream terminal operations also return a Stream. How can we convert a Stream into the desired type? For example, count elements in a Stream and convert that Stream into a collection. To do this, we need terminal operations.

A terminal operation will consume a Stream and generate a final result. That is to say, after a terminal operation is performed on a Stream, the Stream is not reusable and any intermediate operations are not allowed on that Stream. Otherwise, an exception is thrown:

java.lang.IllegalStateException: stream has already been operated upon or closed

This is the same as the meaning of the saying “You cannot step into the same river twice”.

The following table lists the common terminal operations.

Image title

forEach

The forEach method iterates through elements in a Stream. The following code snippet uses forEach to return 10 random numbers:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

count

The count method counts the elements in a Stream.

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis");
System.out.println(strings.stream().count());
//7

collect

The collect operation is a reduce operation that can accept various parameters and accumulate the stream elements into a summary result:

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis");
strings  = strings.stream().filter(string -> string.startsWith("Hollis")).collect(Collectors.toList());
System.out.println(strings);
//Hollis, HollisChuang, Hollis666, Hollis

Next, we still use a figure to show the results of different terminal operations on the Stream given in the preceding example, on which filter, map, sort, limit, and distinct operations have been performed.

The following figure uses an example to show the input and output of all the operations described in this article.

Image title

Summary

This article explains the use and characteristics of Streams in Java 8. Stream creation, stream intermediate operations, and terminal operations are also described in this article.

We can use two methods to create a Stream: using the stream method of a Collection or using the of method of a Stream.

Stream intermediate operations can process Streams. Both the input and the output of intermediate operations are Streams. Intermediate operations include filter, map, and sort.

Stream terminal operations can convert a Stream into some other container, such as counting elements in a Stream, converting a Stream into a collection and iterating through elements in a Stream.

 

Posted in Information Technology

AWS Control Tower

AWS Control Tower

Migrating to AWS can be a big challenge for organizations. Any help with infrastructure, account design, security, and implementing operational controls would be welcomed by many. This is where AWS Control Tower can help. It has been designed to help create and outline a multi-account AWS environment that conforms to best practices defined within the AWS Well-Architected Framework, including security and key operational services as a landing zone.

AWS Control Tower helps ensure that your AWS accounts meet standards required and stipulated by specific compliance controls. It includes the option to adopt and implement AWS Config Rules as a part of the deployment, ensuring specific controls are being met. AWS Config Rules provide a great method to help you enforce specific compliance controls and checks across your resources and allows for you to adopt an “ideal” deployment specification for each of your resource types. Each rule is simply a Lambda function. When called upon, it evaluates the resource and carries out some simple logic to determine the compliance result with the rule. AWS Control Tower will also provide a summary of each AWS account to show its compliance with your policies to show if there is a violation against any AWS Config Rules.

Guardrails

Control Tower also uses a feature known as guardrails within your AWS Organizations organizational unit (OU). These guardrails can be both mandatory and optional to help enforce security compliance and governance across your accounts. Examples of mandatory guardrails include controls such as:

  • Disallowing changes to IAM roles set up for AWS Control Tower
  • Disallowing public read access to log archive
  • Disallowing policy changes to log archive

In addition to these mandatory guardrails, there are also numerous recommended guardrails that you can enable or disable, such as disallowing public write access to Amazon S3 buckets. As well as being either mandatory or optional, these guardrails fall into two categories: preventive and detective. Preventive guardrails stop actions that fail to comply with your policies, and detective guardrails identify non-compliance within your accounts.

AWS Control Tower automatically and efficiently implement new accounts. This can be configured to use other management tools, such as AWS Organizations and AWS Service Catalog, to help you maintain greater control over your AWS environment.

Blueprints

Much of this configuration is simplified in an automated setup through the use of Control Tower blueprints. These best-practice blueprints provide a template configuration centered around AWS security and management services. This helps to deploy your infrastructure using key features, such as federation, logging, audit control, enhanced network design, and workflows to help provision accounts.

Here are a number of examples of what the different blueprints can assist you with:

  • Configure AWS Organizations to create a multi-account environment
  • Provide identity management using AWS SSO Users and Groups
  • Federate access using AWS single sign-on
  • Centralize logging using AWS CloudTrail and AWS Config
  • Enable cross-account security audits using AWS IAM
  • Implement network design using Amazon VPC
  • Define workflows for provisioning accounts using AWS Service Catalog

As a part of the overall management of your multi-account environment, AWS Control Tower allows you to view your infrastructure from a top-level summary via a dashboard which provides information such as:

  • Number of accounts provisioned
  • Number of policies enabled across all of your accounts
  • Compliance status of your accounts

In short, AWS Control Tower is a powerful new addition to the ever-expanding security, identity and compliance category of AWS services to govern and secure multiple AWS accounts. For more information on AWS Config and AWS Organizations, check out the following links:

VPC Traffic Mirroring

Within any organization, security analysts strive to understand what traffic is being generated by resources across the network to discover potential security threats and weaknesses and to troubleshoot incidents. By using AWS virtual private clouds (VPCs), one method of capturing this traffic is to deploy agents across your resources to track and capture network traffic from your EC2 instances. As your environments grow and you deploy more and more VPCs, this approach of agent-based deployments can become very cumbersome and difficult to maintain and manage.

I am pleased to report that AWS has now developed and designed a new solution to resolve this problem. VPC Traffic Mirroring is a new feature within the VPC service, allowing you to duplicate network traffic generated from your resources within your VPC. This traffic can then be sent to another instance or appliance for further analysis and inspection without the use of any third-party agents installed on your resources, simplifying management and control of traffic capturing. VPC Traffic Mirroring is only available on sources running Nitro-based instances.

As this process duplicates traffic, this additional load counts towards your bandwidth associated with the source instance. If your bandwidth limit reaches capacity, causing congestion, then AWS will first drop your mirrored traffic used by VPC Traffic Mirroring to help alleviate the congestion.

Per design best practices, it’s recommended that you forward your duplicated network traffic to a Network Load Balancer (NLB), which then forwards the traffic to a fleet of appliances sitting behind it via a UDP listener. If required, you can simply forward the traffic to a single instance or appliance, but you should design with high availability in mind.

The great thing about VPC Traffic Mirroring is that the instances or appliance that performs the traffic analysis can be in a different VPC than that of the source generating the traffic. This allows you to achieve a hub and spoke design, drawing in traffic collated from multiple different VPCs all being directed from a single VPC dedicated for security analysis and detecting network anomalies. Again, this design helps with management and control of your resources.

Mirror Filter

With added configurational parameters, it’s possible to implement mirror filtering to allow you to specify which network packets you are interested in capturing. For example, if you want to analyze all traffic using a specific port and protocol, such as SSH, then this could be configured via a mirror filter.

Any traffic that matches the mirror filter criteria would be captured, and any that didn’t would be dropped at the source. This prevents your appliances and instances from having to analyze ALL traffic generated by a resource when you may only be interested in a specific subset of the traffic.

Components

The components used within VPC Traffic Mirroring are easy to define. Firstly, we need a source. This can be any resource within your VPC which uses an Elastic Network Interface (ENI), such as an EC2 instance.

You must also have a mirror target as well, which is where the traffic will be sent. As I explained earlier, this would generally be a network load balancer, but you can specify an ENI of another instance or appliance as required. This target can even be in a different VPC from the source.

To restrict which traffic is captured at your source, you can set and configure your mirror filters which are created as rules, based on protocols, ranges, and CIDR blocks. These rules are then read in order and the appropriate action is taken as soon as a match is found, much like a network access control list (NACL).

The final component is a mirror session. This essentially defines the logical connection between a source and a target and it’s associated mirror filters. You can create more than one mirror session for a source. For example, as shown in the diagram below, you can create a mirror session (Mirror session 1) that captures all TCP traffic from Source A to Target A. Then another mirror session (Mirror session 2) captures all UDP traffic from Source A (again) but to a different Target: Target B.

This might be helpful if you have different tools on each target that you will use to analyze different types of traffic. However, be aware there is a limit of three mirror sessions per ENI.

Being able to monitor network traffic across multiple VPCs without having to implement agents on monitored resources simplifies network analysis for incident identification and resolution, security anomalies, and compliance. The ability to couple this configuration with existing security tools obtained from the AWS Marketplace makes this a very powerful tool in the security of VPCs.

Posted in Information Technology

Spring Annotations

The complexity of modern applications never ceases to grow, with more and more features being packed into single applications or groups of applications. Although this growth brings with it some fantastic benefits, such as rich functionality and impressive versatility, it requires that developers utilize an ever-increasing number of paradigms and libraries. To reduce the workload of developers — and the amount of information that developers must memorize — many Java frameworks have turned to annotations.

Spring, in particular, is renowned for its use of annotations, allowing developers to create entire Representational State Transfer (REST) Application Programming Interfaces (APIs) with only a handful of annotations. These annotations reduce the amount of boilerplate code that is required to perform essential functions, but it also can obscure what is happening behind the scenes. For example, how does applying a Dependency Injection (DI) annotation to a field result in a specific bean being injected at runtime? Or, how does a REST annotation know which URL path to bind to?

Although these questions may appear to be specific to Spring — which begs the question of why a non-Spring developer would need to know an answer to them — they are more far-reaching than meets the eye. According to a 2018 survey conducted by Baeldung, 90.5 percent of the participants were using Spring. Additionally, according to the 2019 Stackoverflow Developer’s Survey, 16.2 percent of all developers surveyed use Spring, and 65.6 percent say they love Spring. The ubiquity of Spring means that even Java developers that use another framework or do not require any enterprise framework at all are likely to come across Spring code. Even Spring developers whose knowledge is confined to a small subset of the Spring annotations will benefit from expanding their horizons.

In this article, we will dive into four of the most pertinent annotations that are available in Spring, paying particular attention to the concepts behind the annotation and how to properly apply the annotation in the context of a larger application. While we will go into detail on each of these annotations and their associated annotations, the wealth of information on Spring annotations is staggering and could not be contained in this single article. The interested reader should consult the official Spring documentation for more details.

1. @Component

At its heart, Spring is a DI framework. In essence, a DI framework is responsible for injecting dependencies— in the form of Java beans — into other beans. This paradigm is the opposite of most basic applications, which directly instantiate their dependencies. In DI, however, beans are created with a level of indirection, expecting a DI framework to inject the dependencies for them. For example, a well-designed bean would have a constructor with a parameter for the dependency — and allow the DI framework to pass in an object that satisfies that dependency upon construction — rather than directly instantiating the dependency in the constructor. This reversal is called Inversion of Control (IoC) and is the basis upon which many of the various Spring libraries rest:

public class Bar {}

// The non-DI way
public class Foo {

    private final Bar bar;

    public Foo() {
        this.bar = new Bar();
    }
}

// The DI way
public class Foo {

    private final Bar bar;

    public Foo(Bar bar) {
        this.bar = bar;
    }
}

One of the most critical questions for a DI framework to answer is: Which beans are candidates to be injected into other beans? To answer this question, Spring provides the @Component annotation. Applying this annotation to class informs Spring that the class is a component and an object of this class can be instantiated and injected into another component. The @Component interface is applied to a class in the following manner:

@Component
public class FooComponent {}

Although the @Component annotation suffices to inform Spring of the injectability of a bean; Spring also provides specialized annotations that can be used to create components with more meaningful contextual information.

@Service

The @Service annotation — as the name implies — denotes that a bean is a service. According to the official @Service annotation documentation:

[The @Service annotation] indicates that an annotated class is a “Service”, originally defined by Domain-Driven Design (Evans, 2003) as “an operation offered as an interface that stands alone in the model, with no encapsulated state.”

May also indicate that a class is a “Business Service Facade” (in the Core J2EE patterns sense), or something similar.

In general, the concept of service in enterprise applications is vague, but in the context of a Spring application, a service is any class that provides methods to interact with domain logic or external components without maintaining state that changes the overall behavior of the service. For example, a service may act on behalf of an application to obtain documents from a database or obtain data from an external REST API.

@Service
public class FooService {}

While there is no definitive rule about the state of a service, services generally do not contain state in the way that domain objects do. For example, a REST client, cache, or connection pool would not be considered the state of a service in the same way that a name, address, and social security number would be regarded as the state of a domain object. In practice, @Service and @Component are often used interchangeably due to the all-encompassing definition of a service.

@Repository

While @Service is intended for more a general purpose, the @Repository annotation is a specialization of the @Component annotation that is designed for components that interact with data sources, such as databases, and Data Access Objects (DAOs).

@Repository
public class FooRepository {}

According to the official @Repository documentation:

Indicates that an annotated class is a “Repository”, originally defined by Domain-Driven Design (Evans, 2003) as “a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects”.

Teams implementing traditional Java EE patterns such as “Data Access Object” may also apply this stereotype to DAO classes, though care should be taken to understand the distinction between Data Access Object and DDD-style repositories before doing so. This annotation is a general-purpose stereotype and individual teams may narrow their semantics and use as appropriate.

Apart from marking a specific class as a component dealing with data sources, the Spring Framework treats beans annotated with @Repository with special exception processing. To maintain a consistent data interface, Spring can translate the exceptions thrown by native repositories — such as SQL or Hibernate implementations — into general exceptions that can be handled uniformly. To include exception translation for classes annotated with @Repository, we instantiate a bean of type PersistenceExceptionTranslationPostProcessor (we will see in later sections how to use the @Configuration and @Bean annotations):

@Configuration
public class FooConfiguration {

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslator() {
        return new PersistenceExceptionTranslationPostProcessor()
    }
}

Including this bean will inform Spring to look for all implementations of PersistenceExceptionTranslator and use these implementations, if possible, to translate native RuntimeExceptions into DataAccessExceptions. For more information on exception translation with the @Repository annotation, see the official Spring Data Access documentation.

@Controller

The last specialization of the @Component annotation is arguably the most commonly used of the trio. Spring Model-View-Controller (MVC) is one of the most popular portions of the Spring Framework and allows developers to easily create REST APIs using the @Controller annotation. This annotation, when applied to a class, instructs the Spring Framework that the class should be treated as a part of the web interface for the application.

Endpoints are created in this class by applying the @RequestMapping annotation to the methods of that class — where the value of the @RequestMapping annotation is the path (relative to the root path of the controller to which the API endpoints are bound), and the method is the Hypertext Transfer Protocol (HTTP) method to which the endpoint is bound. For example:

@Controller
public class FooController {

    @RequestMapping(value = "/foo", method = RequestMethod.GET)
    public List<Foo> findAllFoos() {
        // ... return all foos in the application ... 
    }
}

This would create an endpoint that listens on the /foo path for GET requests and returns a list of all Foo objects — represented as a JavaScript Object Notation (JSON) list by default — to the caller. For example, if the web application was started on https://localhost, the endpoint would be bound to https://localhost/foo. We will cover the @RequestMapping annotation in greater detail below, but for the time being, it suffices to know that the @Controller annotation is a potent part of the Spring Framework and one that instructs the Spring Framework to create large and complex web service implementations on our behalf.

@ComponentScan

As described in Creating Annotations in Java, annotations do not execute any logic in-and-of themselves. Instead, annotations are simply markers that denote some information about a construct, such as a class, method, or field. For the annotation to be useful, it must be processed. In the case of the @Component annotation — and its specializations — Spring does not know where to look to find all of the classes annotated with @Component.

To do so, we must instruct Spring which packages on the classpath should be scanned. During the scanning process, the Spring DI Framework processes each of the classes in the provided package, recording any classes that are annotated with @Component or specialization of @Component. Once the scanning process is complete, the DI framework is aware of which classes are eligible for injection.

To instruct Spring which packages to scan, we use the @ComponentScan annotation:

@Configuration
@ComponentScan
public class FooConfiguration {
    // ...
}

In a later section, we will delve into the @Configuration annotation, but for the time being, it suffices to know that the @Configuration annotation instructs Spring that the annotated class provides configuration information to be used by the DI framework. By default — if no arguments are supplied to the @ComponentScan annotation — the package that contains the configuration, and all its subpackages, are scanned. To specify a package or set of packages, the basePackages field is used:

@Configuration
@ComponentScan(basePackages = "com.example.foo")
public class FooConfiguration {
    // ...
}

In the above example, Spring would scan the package com.example.foo and all of its subpackages for eligible components. If only one base package is provided, the @ComponentScan annotation can be simplified to @ComponentScan("com.example.foo"). If more than one base package is required, the basePackages field can be assigned a set of strings:

@Configuration
@ComponentScan(basePackages = {"com.example.foo", "com.example.otherfoo"})
public class FooConfiguration {
    // ...
}

2. @Autowired

A second, vital question for any DI framework is: What are the dependencies that must be satisfied when creating a bean? To inform the Spring Framework which fields or constructor parameters we are expecting to be injected — or wired — with dependencies, Spring provides the @Autowired annotation. This annotation is usually applied to either fields or constructors — although it can be applied to setters as well (this usage is less common).

When applied to fields, Spring will inject a qualifying dependence directly into the field upon creation, even when there is no setter present:

@Component
public class FooComponent {

    @Autowired
    private Bar bar;
}

This is a convenient means of injecting dependencies into a component, but it does create an issue when testing a class. For example, if we were to write a test fixture that exercises our FooComponent class, without including the Spring testing framework into our fixture, we would be unable to inject a mock Bar value into the bar field (without performing cumbersome reflection). We could instead add the @Autowired annotation to a constructor that accepts a Bar parameter and assigns it to the bar field:

@Component
public class FooComponent {

    private final Bar bar;

    @Autowired
    public Foo(Bar bar) {
        this.bar = bar;
    }
}

This still allows us to directly instantiate objects of the FooComponent class with mock Bar implementations without burdening the fixture with Spring test configuration. For example, the following would be a valid JUnittest case (using Mockito for mocking):

public class FooTest {

    @Test
    public void exerciseSomeFunctionalityOfFoo() {

        Bar mockBar = Mockito.mock(Bar.class);
        FooComponent foo = new FooComponent(mockBar);

        // ... exercise the FooComponent object ...
    }

Annotating the constructor with @Autowired also allows us to access and manipulate the injected Bar bean before assigning it to the bar field. For example, if we wanted to ensure that the injected Bar bean is never null, we can perform this check prior to assigning the supplied Bar bean to the bar field:

@Component
public class FooComponent {

    private final Bar bar;

    @Autowired
    public FooComponent(Bar bar) {
        this.bar = Objects.requireNonNull(bar);
    }
}

@Qualifier

In some instances, there may be multiple candidates for a dependency. This causes a problem for Spring since it must decide on which specific beans to inject when creating a component, or fail if a single candidate cannot be decided upon. For example, the following code will throw a NoUniqueBeanDefinitionException:

public interface FooDao {
    public List<Foo> findAll();
}

@Repository
public class HibernateFooDao implements FooDao {

    @Override
    public List<Foo> findAll() {
        // ... find all using Hibernate ...
    }
}

@Repository
public class SqlFooDao implements FooDao {

    @Override
    public List<Foo> findAll() {
        // ... find all using SQL ...
    }
}

@Controller
public class FooController {

    private final FooDao dao;

    @Autowired
    public FooController(FooDao dao) {
        this.dao = dao;
    }
}

Spring would not know whether to inject the HibernateDooDao or the SqlFooDao and would, therefore, throw a fatal NoUniqueBeanDefinitionException. To aid Spring in resolving which bean to select, we can use the @Qualifier annotation. By supplying a key to @Qualifier annotation that matches the name supplied to the @Component annotation (or any of its specialization) in conjunction with the @Autowired annotation, we can narrow the eligible injection candidates. For example, in the following snippet, the HibernateFooDao would be injected into the FooController and no NoUniqueBeanDefinitionException would be thrown:

public interface FooDao {
    public List<Foo> findAll();
}

@Repository("hibernateDao")
public class HibernateFooDao implements FooDao {

    @Override
    public List<Foo> findAll() {
        // ... find all using Hibernate ...
    }
}

@Repository("sqlDao")
public class SqlFooDao implements FooDao {

    @Override
    public List<Foo> findAll() {
        // ... find all using SQL ...
    }
}

@Controller
public class FooController {

    private final FooDao dao;

    @Autowired
    @Qualifier("hibernateDao")
    public FooController(FooDao dao) {
        this.dao = dao;
    }
}

3. @Configuration

Due to the enormous scale of the Spring Framework — dealing with everything from DI to MVC to transaction management—a level of developer-supplied configuration is needed. For example, if we wish to define a set of beans that can be used for autowiring — such as the PersistenceExceptionTranslationPostProcessor bean seen above — we must inform Spring with some configuration mechanism. Spring provides this mechanism through the aptly named @Configuration annotation. When this annotation is applied to a class, Spring treats that class as if it contains configuration information that can be used to parameterize the framework. According to the official Spring @Configuration documentation:

Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime, for example:

@Bean

As we saw above, we can manually create new beans that Spring will include as candidates for injection without annotating the class itself. This may be the case when we do not have access to the source code for the class or the class exists in a package that is not part of the component scanning process. In the case of our @Qualifier example above, we could also forego the @Repository annotations and use the @Bean annotation inside a class annotated with @Configuration to instruct Spring to use the HibernateFooDao when a FooDao is needed:

public interface FooDao {
    public List<Foo> findAll();
}

public class HibernateFooDao implements FooDao {

    @Override
    public List<Foo> findAll() {
        // ... find all using Hibernate ...
    }
}

public class SqlFooDao implements FooDao {

    @Override
    public List<Foo> findAll() {
        // ... find all using SQL ...
    }
}

@Configuration
public class FooConfiguration {

    @Bean
    public FooDao fooDao() {
        return new HibernateFooDao();
    }
}

Using this configuration, Spring will now have the logic necessary to instantiate a HibernateDooDao when a FooDao is requested. In essence, we have created a Factory Method that the framework can use to instantiate instances of FooDao when needed. If an @Autowired parameter is excepted when creating a bean, we can object that dependency by adding a parameter to the method annotated with @Bean. If we annotate the component with @Component — or any specialization of @Component — Spring would know to inject the dependency when creating the component, but because we are calling the constructor directly — outside the Spring Framework — we must supply the dependency. For example:

@Component
public class Bar {}

public class FooComponent {

    private final Bar bar;

    @Autowired
    public FooComponent(Bar bar) {
        this.bar = bar;
    }
}

@Configuration
public class FooConfiguration {

    @Bean
    public FooComponent fooComponent(Bar bar) {
        return new FooComponent(bar);
    }
}

Spring looks for registered candidates that satisfy the fooComponent method parameters and when one is found, it is passed in and eventually passed to the FooComponent constructor. Note that any bean annotated with @Component — or any specialization — or a bean created using another @Bean method can be injected into the @Bean method parameters. For example:

public class Bar {}

public class FooComponent {

    private final Bar bar;

    @Autowired
    public FooComponent(Bar bar) {
        this.bar = bar;
    }
}

@Configuration
public class FooConfiguration {

    @Bean
    public Bar bar() {
        return new Bar();
    }

    @Bean
    public FooComponent fooComponent(Bar bar) {
        return new FooComponent(bar);
    }
}

Note that is a convention to name the method annotated with @Bean the same as the bean, with the first letter lowercase. For example, if we are creating a FooComponent, the method used to create the bean — and annotated with @Bean — is usually called fooComponent.

4. @RequestMapping

A large portion of the functionality of the @Controller annotation is derived from the @RequestMappingannotation, which instructs Spring to create a web endpoint that maps to the annotated method. When creating web API, a framework needs to know how to handle requests made to a specific path. For example, if an HTTP GET call is made to https://localhost/foo, Spring needs to know how to handle that request. This binding — or mapping — process is the purview of the @RequestMapping annotation, which informs Spring that a specific HTTP verb and path should be mapped to a specific method. For example, in a previous section, we saw that we could instruct Spring to map an HTTP GET to /foo using the following snippet:

@Controller
public class FooController {

    @RequestMapping(value = "/foo", method = RequestMethod.GET)
    public List<Foo> findAll() {
        // ... return all foos in the application ... 
    }
}

Note that multiple HTTP verbs can be supplied to the method parameter, but this is abnormal in practice. Since a single HTTP verb is almost always provided to the method parameter — and these verbs usually end up being GETPOSTPUT, and DELETE — Spring also includes four additional annotations that can be used to simplify the creation of @RequestMapping methods:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping

If a root path is desired (i.e. a path matching the path of the controller), no value parameter is needed. The @RequestMapping annotation can also be applied to the controller itself, which sets the root path for the entire controller. For example, the following controller creates a GET endpoint at the /foo path and another POSTendpoint at /foo/bar:

@Controller
@RequestMapping("/foo")
public class FooController {

    @GetMapping
    public List<Foo> findAll() {
        // ... return all foos in the application ... 
    }

    @PostMapping("/bar")
    public void doSomething() {
        // ... do something ...
    }
}

@PathVariable

In some cases, a path variable may be supplied in the path, which is needed for properly handling the request. To obtain the value of this path variable, a parameter can be provided to the method annotated with @RequestMapping and the @PathVariable annotation can be applied to this parameter. For example, if the ID of an entity is needed to DELETE it, the ID can be provided as a path variable, such as a DELETE request to /foo/1. In order to capture the 1 supplied to the method responsible for handling the DELETE request, we capture the path variable by enclosing the variable name with curly braces and applying the @PathVariable annotation for a parameter of the handler method, where the value supplied to the @PathVariable matches the name of the variable captured in the path:

@Controller
public class FooController {

    @DeleteMapping("/foo/{id}")
    public void deleteById(@PathVariable("id") String id) {
        // ... delete Foo with ID "id" ... 
    }
}

By default, the name of the @PathVariable is assumed to match the name of the annotated parameter, so if the name of the parameter exactly matches the name of the captured variable in the path, no value needs to be supplied to @PathVariable annotation:

@Controller
public class FooController {

    @DeleteMapping("/foo/{id}")
    public void deleteById(@PathVariable String id) {
        // ... delete Foo with ID "id" ... 
    }
}

Spring will attempt to coerce the captured path variable into the data type of the parameter annotated with @PathVariable. For example, if we except the value of the ID path variable to be an integer, we could change the data type of the id parameter to int:

@Controller
public class FooController {

    @DeleteMapping("/foo/{id}")
    public void deleteById(@PathVariable int id) {
        // ... delete Foo with ID "id" ... 
    }
}

If a value, such as the string baz, is supplied in the path (i.e., /foo/baz), an error will occur.

@RequestParam

Apart from capturing path variables, we can also capture query parameters using the @RequestParamannotation. The @RequestParam decorates a parameter to the handler method in the same manner as the @PathVariable annotation, but the value supplied to the @RequestParam annotation matches the key of the query parameter. For example, if we expect that an HTTP GET call will be made to a path of /foo?limit=100, we can create the following controller to capture the limit value:

@Controller
public class FooController {

    @GetMapping("/foo")
    public List<Foo> findAll(@QueryParam("limit") int limit) {
        // ... return all Foo objects up to supplied limit ... 
    }
}

Just as with @PathVariable, the value supplied to the @RequestParam annotation can be omitted, and the name of the parameter will be used by default. Likewise, Spring will coerce the value of the captured query parameter into the type of the parameter, if possible (in the case above, to int).

@RequestBody

In cases where a request body is supplied in a call —commonly done with POST or PUT calls that create or update entries — Spring provides the @RequestBody annotation. As with the previous two annotations, the @RequestBody annotation is applied to a parameter of the handler method. Spring will then deserialize the supplied request body into the type of the parameter. For example, we can create a new Foo with an HTTP call that has a request body similar to the following:

{"name": "some foo", "anotherAttribute": "bar"}

We can then create a class that encompasses fields that match the expected request body and create a handler method that captures this request body:

public class FooRequest {

    private String name;
    private String anotherAttribute;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAnotherAttribute(String anotherAttribute) {
        this.anotherAttribute = anotherAttribute;
    }

    public String getAnotherAttribute() {
        return anotherAttribute;
    }
}

@Controller
public class FooController {

    @PostMapping("/foo")
    public void create(@RequestBody FooRequest request) {
        // ... create a new Foo object using the request body ...
    }
}

Coda

Although there are many Java frameworks, Spring is far and away, one of the most ubiquitous. From REST APIs to DI, Spring includes a rich set of features that allow developers to create complex applications without writing reams of boilerplate code. One mechanism that Spring provides is annotations, which enables developers to decorate classes and methods and provide them with contextual information that can be consumed by the Spring Framework to create components and services on our behalf. Due to the universality of Spring, every Java developer can significantly benefit from understanding these Spring annotations and how they are applied in practice.

Posted in Information Technology

Agile beyond IT

These days, Agile has grown beyond the IT sector and is being successfully applied in marketing, sales management, logistics, corporate governance, and more.

Agile encompasses both the culture and the methodology that allows companies to adapt to the changes in the most effective manner.

No matter where Agile methodology is applied — whether it is dentistry, banking, sales management, or marketing — Agile always stands for creating value for clients as well as creating value for teams.

Agile does not only enhance the quality of the business processes of the company, but it also ensures their maximum transparency. Only when it is possible to see the clarity of interactions, the team members are able to truly discuss the issues hidden under the table, namely the ineffective instruments, and insist on the urgency of change.

Agile adventure

Even the least developed industries impacted by Agile can undergo a successful transformation. Our team faced a similar task when we risked implementing Agile in a large medical company. It was a true adventure as never before had anyone used Agile in the medical sector!

Frankly speaking, medicine has been standing behind other financial industries.

Even though medicine has always been deemed commercially viable, it was still benched when it came to applying new technologies and business-tools, making bold personnel decisions, or starting innovative marketing activities.

We decided to take a risk, even though at that time we did not have a clear picture of the potential outcome of our endeavors.

Initially, the company management ordered us to conduct a three-day training session. We ended up teaching the top-management, including the branch managers and the industrial directors, about Agile and its tools. After the training, the company attempted to implement Agile on their own; yet, it did not truly fly, so the company turned to me for additional consultations.

For the pilot project, we chose the clinic that demonstrated the worst financial performance. The goal was to show how much Agile can increase not only the turnover but also the commitment displayed by the employees. To measure effectiveness, we introduced several criteria (KPI): financial plan performance, the number of the patients, the number of referrals, and so on.

agile at the doctor&apos;s office

The first thing we did upon arriving to the clinic was diving the employees into three groups. Out of 35 people representing the clinic staff, we managed to create three cross-functional teams.

One team consisted of the chief doctor as well as the security guards, while the other one had the assistant doctor and the janitor. The employees were grouped based on the shifts they usually shared during their working hours, so each team consisted of the people who interacted with one another on the regular basis.

We chose the scrum masters, the team leaders responsible for all the processes happening within the group, and the product owner, who was responsible for the overall vision of the assignment, targeting as well as prioritizing the task in response to the feedback received the clients.

Each team was assigned a sprint, i.e. certain periods of time which coincided with the project work. Likewise, each team went through the daily meetings, namely daily 15-minute meetings where the participants had to be literally standing, the demo where the team was to demonstrate the results of their work in front of the other clinics, and the retrospective sessions where the in-depth analysis of the weekly work was taking place.

The clinic team was faced with clearly defined goals:

  • 100 percent performance of the plan (as opposed to the 43 percent performance demonstrated by the clinic at the beginning of the project work)
  • increase the number of the first-time patients
  • launch the surgery room
  • increase the number of the referrals
  • instill the culture that celebrates the values important to the clients as well as philosophy of leadership and mentorship
  • create the marketing division

Additionally, we were faced with the global task of instilling Agile values into the whole chain of the clinics. That is why we opted to install cameras in negotiating rooms where the pilot project participants were to get together.

Thus, all events were recorded and broadcast to the members of the closed community on Facebook. This way, every branch had the access to these educational videos.

We were able to record (and demonstrate) almost everything, with the exception of personal meetings with those team members where the inner conflicts and the complicated situations interfered in the discussion.

This was a real PR-campaign to introduce Agile to every employee of the clinic.

Problems and solutions

Despite the positive attitude the top management of the clinic demonstrated towards our project, there still were several difficulties we had to encounter. Since it was still too far from accomplishing the goals in question, we had to focus on surmounting the local barriers.

One of the barriers dealt with the total absence of the culture of leadership in the company:

It turned out that there was not a single person in the clinic who was readyto lead the others. None of the eight managers was ready to shoulder that kind of responsibility.

When applying Scrum, we redefined the structure of the company, thus limiting the number of managerial roles and appointing three scrum masters and one product owner. One of the chosen ones had to assume the role of the leader of all the changes to be happening in the clinic; however, no one seemed to be ready to shoulder that kind of responsibility.

In three months after the launch of Agile, the expected transformation stalled: The employees did not know what their further actions ought to have been. The people seemed to have cooled off, and the performance indicators decreased as well — the plan was performed by no less than 40 percent.

The teams blamed it all on Agile as supposedly the discussions had taken a huge chunk of employee’s work time. It was quite difficult to keep their faith into moving forward when the old system proved to be unworkable, yet the new one had not been established while the performance numbers kept decreasing.

The lack of motivation and overall negativity stirred up not just at this particular branch, but at the whole chain of clinics. One of the founders (and Agile supporters) visited the pilot clinic, organized a meeting of the employees and asked them point-blank, “Who wants to continue to participate in the project? Not just be a part of it, but pay for the changes? Let’s vote!”

It’s worth noting the doctors’ incomes were in direct proportion to the profits made by the clinic, while the service of the Agile specialists should have been paid for.

60 percent of the employees voted in favor of the changes implemented by the Agile methodology, and the director turned out to be the leader who managed to take the whole situation to the next level.

Only then did the Agile transformation work to its fullest, resulting in the change of the way the whole clinic operated.

All things considered, upon applying the Agile principles, the pilot clinic changed beyond recognition. By the end of the accounting period, the plan performance of the clinic equaled 105 percent. This was the record not only for the branch, but also for the whole chain, and this happened because every employee was involved in the process.

Results

First of all, an open line of communication was successfully established among all the employees. This partially resulted from teaming up the people regardless of their position within the company; this way, we managed to get rid of managerial roles and official ranking and overcome the hierarchy.

In fact, only one person was “in charge” — the product owner — whose task was assumed by the director of the clinic.

And the director did not impose the way the clinic was to fulfill the plan but rather worked towards creating values.

Second of all, the commitment displayed by the employees drastically increased. Once the people realized they were capable of impacting the company’s performance directly, their engagement in the work process doubled.

Let us see how that was achieved:

A security guard started welcoming patients and inquiring about their health and mood, whereas before he appeared uninterested. Now, smiling and joking, he helped the patients to their seats and even turned on a TV program while the patients were waiting.

Before, the doctors at the clinic did not communicate much with each other. More experienced doctors who enjoyed a wide patient stream did not fancy sharing the knowledge while the young doctors were too reluctant to ask for advice. Everyone worked by themselves and for themselves.

Besides, there was a certain caste system in the clinic: Medical assistants and even younger doctors were perceived as the lowest class. All in all, no one truly interacted with anyone.

Only after Agile was introduced into the system, the situation changed. In a way, Agile served as a wake-up call for the employees: Stereotypes were dissolved and client-oriented values were formed.

Patients always know if the doctor and the medical assistant display mutual respect. If they don’t work together as a team, the quality of the provided treatment tends to suffer as well.

So, after we started organizing daily meetings where the people involved in the process were providing the feedback, the doctors realized the importance of the real team work. Likewise, the doctors saw the significance of the joint effort in both increasing the quality of the service as well as boosting the patients’ mood. As a result, the clients started recommending the clinic to their friends and acquaintances.

The number of patient referrals went up as well. Before, the doctors did not put much thought into that aspect of work. Yet, after the doctors started interacting and communicating, as well as participating in the daily meetings, that situation changed too. Finally, the doctors began cooperating. For instance, a physician started the practice of referring his/her patient to the orthodontist and vice versa, as to make a precise diagnosis, sometimes one needs to consult several specialists.

The project team initiated the system of knowledge-sharing. Before, specialists who had participated in the scientific conferences or attended training courses would keep the acquired information and experience to themselves; yet now he or she would share the valuable material with colleagues.

As a result, the clinic has become the core of the whole chain. The total number of improvements achieved by the pilot clinic during the whole project period amounted to 260. For example, the doctors started to call patients directly (as opposed to referring that task to the receptionists).

The overall results of the project, including financial performance, drew the attention of other branches: the employees of the whole chain ended up coming to the clinic in order to learn new tools and work according to the new rules.

agile at the doctor&apos;s office

Further reading

The Importance of Agile Leaders

How to Ensure Digital Transformation Success: Build an Engaged Workforce

Posted in Information Technology

Thread Confinement

Thread Confinement

Most concurrency problems occur only when we want to share a mutable variable, or mutable state, between threads. If a mutable state is shared between multiple threads, then all of them will be able to read and modify the value of the state, thus resulting in incorrect or unexpected behavior. One way to avoid this problem is to simply not share the data between the threads. This technique is known as thread confinement and is one of the simplest ways of achieving thread safety in our application.

The Java language, in itself, does not have any way of enforcing thread confinement. Thread confinement is achieved by designing your program in a way that does not allow your state to be used by multiple threads and is, thus, enforced by the implementation. There are a few types of thread confinement, as described below.

Ad-Hoc Thread Confinement

Ad-hoc thread confinement describes a way of thread confinement, where it is the total responsibility of the developer, or the group of developers working on that program, to ensure that the use of the object is restricted to a single thread. This approach is very very fragile and should be avoided in most cases.

One special case that comes under Ad-hoc thread confinement applies to volatile variables. It is safe to perform read-modify-write operations on the shared volatile variable as long as you ensure that the volatile variable is only written from a single thread. In this case, you are confining the modification to a single thread to prevent race conditions, and the visibility guarantees for volatile variables ensure that other threads see the most up to date value.

Stack Confinement

Stack confinement is confining a variable, or an object, to the stack of the thread. This is much stronger than Ad-hoc thread confinement, as it is limiting the scope of the object even more, by defining the state of the variable in the stack itself. For example, consider the following piece of code:

private long numberOfPeopleNamedJohn(List<Person> people) {
  List<Person> localPeople = new ArrayList<>();
  localPeople.addAll(people);

  return localPeople.stream().filter(person -> person.getFirstName().equals("John")).count();
}

In the above code, we pass on a list of person but do not directly use it. We, instead, create our own list, which is local to the currently executing thread, and add all the person in people to localPeople. Since we are defining our list in the  numberOfPeopleNamedJohn method only, this makes the variable  localPeople stack confined, as it exists on stack of one thread, and thus cannot be accessed by any other thread. This makes localPeople thread safe. The only thing we need to take care of here is that we should not allow localPeople to escape the scope of this method, to keep it stack confined. This should also be documented or commented when defining this variable, as generally, it’s only in the current developer’s mind to not let it escape, and in future, another developer may mess up.

ThreadLocal

ThreadLocalallows you to associate a per-thread value with a value-holding object. It allows you to store different objects for different threads and maintains which object corresponds to which thread. It has set and get accessor methods which maintain a separate copy of the value for each thread that uses it. The  get() method always returns the most updated value passed to  set() from the currently executing thread. Let’s look at an example:

public class ThreadConfinementUsingThreadLocal {

    public static void main(String[] args) {
        ThreadLocal<String> stringHolder = new ThreadLocal<>();

        Runnable runnable1 = () -> {
            stringHolder.set("Thread in runnable1");
            try {
                Thread.sleep(5000);
                System.out.println(stringHolder.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Runnable runnable2 = () -> {
            stringHolder.set("Thread in runnable2");
            try {
                Thread.sleep(2000);
                stringHolder.set("string in runnable2 changed");
                Thread.sleep(2000);
                System.out.println(stringHolder.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Runnable runnable3 = () -> {
            stringHolder.set("Thread in runnable3");
            try {
                Thread.sleep(5000);
                System.out.println(stringHolder.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Thread thread1 = new Thread(runnable1);
        Thread thread2 = new Thread(runnable2);
        Thread thread3 = new Thread(runnable3);

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

In the above example, we have executed three threads, using the same  ThreadLocal object stringHolder. As you can see here, we have, first of all, set one string in every thread in the stringHolder object, making it contain three strings. Then, after some pause, we have changed the value from just the second thread. Below was the output of the program:

string in runnable2 changed
Thread in runnable1
Thread in runnable3

As you can see in the above output, the String for thread 2 changed, but the strings for thread 1 and thread 3 were unaffected. If we do not set any value before getting the value on a specific thread from ThreadLocal, then it returns null. After a thread is terminated, thread-specific objects in ThreadLocal become ready for garbage collection.

Posted in Information Technology

A Production-Ready Checklist for Kubernetes

How do you know when you’re ready to run your Kubernetes cluster in production? In this blog series, we’re going to look at what’s typically included in a Production Readiness checklist for your cluster and your app.

These checklists were put together by Brice Fernandes (@fractallamda), a Weaveworks customer success engineer. If you’re lucky enough to attend an upcoming hands-on workshop led by Brice, production readiness will be a topic that he’ll be deep diving on.

In part 1 of this blog series, we’ll look at production-ready checklists for clusters. In part 2, we’ll drill down on what to include on an application checklist.

What is Production-Ready?

Production readiness is a term you hear a lot, and depending on who you are talking to and what they are doing, it can mean different things.

“Your offering is production-ready when it exceeds customer expectations in a way that allows for business growth.” —  Carter Morgan , Developer Advocate, Google.

Cluster production readiness is somewhat dependant on your use case and can be about making tradeoffs. Although a cluster can be production-ready when it’s good enough to serve traffic, many agree that there are a minimum set of requirements you need before you can safely declare your cluster ready for commercial traffic.

When creating a reliable production set-up, the following areas are important. Some of these topics will be more important than others, depending on your specific use case.

  1. Keep security vulnerabilities and attack surfaces to a minimum. Ensure that the applications you are running are secure and that the data you are storing, whether it’s your own or your clients, is secured against attack. In addition to this, be aware of security breaches within your own development environments. And because Kubernetes is a rapidly growing open source project, you’ll also need to be on top of the updates and patches so that they can be applied in a timely manner.
  2. Maximize portability and scalability by fine-tuning cluster performance. Running and managing applications anywhere is why Kubernetes is the number one orchestrator, as is its ability to self-heal nodes, autoscale infrastructure and adapt to your expanding business. Most want all of the benefits of self-healing and scalability without taking a performance hit.
  3. Implement secure CI/CD pipelines for continuous delivery. With your infrastructure in place, an automated continuous deployment and delivery pipeline allows your development team to maximize their velocity and improve productivity through increased release frequency and repeatable deployments.
  4. Apply observability as a deployment catalyst. Observability is not only about being able to monitor your system, but it’s also about having a high-level view into your running services so that you can make decisions before you deploy. To achieve true observability you need the processes and tools in place to act on that monitoring through timely incident alerts.
  5. Create a disaster recovery plan. Ensure that you have high availability which means that if you have a failure your cluster can recover automatically. In the case of complete cluster meltdown with the adoption of GitOps best practices.

The Production-Ready Checklist for Clusters

These are the areas that need attention before running your cluster in production.

WHAT IS IT WHY YOU NEED IT OPTIONS
Build Pipeline Tests, integrates, builds and deposits container artefact to registry.
Artefacts should be tagged with Git commit SHA to verify provenance
Ensures a bug free artefact before deployment. CircleCI
Travis
Jenkins
and others.
Deployment pipeline Takes the build artefacts, and delivers them to the cluster. This is where GitOps occurs. More secure way of doing deployment. Can add approval checkpoints if needed. Weave Cloud
Flux
Image Registry Stores build artefacts.
Needs credentials for CI to push and for cluster to pull images.
Keeps versioned artefacts available. Roll your own
Commercial:
DockerHub
JFrog
GCP Registry
Monitoring Infrastructure Collects and stores metrics. Understands your running system. Alerts when something goes wrong. OSS:
Prometheus
Cortex, 
Thanos 

Commercial: 
Datadog

Grafana Cloud

Weave Cloud

Shared Storage Stores the persistent state of your application beyond the pod’s lifetime.
Seen by your app as a directory and can be read-only.
No one ever has a stateless app. Many.
Depends on the platform.
Secrets management How your applications access secret credentials across your application and to and from the cluster. Secrets are required to access external services. Bitnami sealed secrets.
Hashicorp Vault.
Ingress controller Provides a common routing point for all inbound traffic. Easier to manage authentication and logging. AWS ELB
NGINX 

Kong

Traefik

HAProxy

Istio
API Gateway Creates a single point for incoming requests and is a higher level ingress controller that can replace an ingress controller. Routes at HTTP level. Enables common and centralized tooling for tracing, logging, authentication. Ambassador (Envoy)

Roll your own

Service Mesh Provides an additional layer on top of Kubernetes to manage routing. Enables complex use cases like Progressive Delivery. Adds inter-service TLS, Load balancing, service discovery, monitoring and tracing. Linkerd
Istio
Service catalogue / Broker Enables easy dependencies on services and service discovery for your team Simplifies deploying applications. Kubernetes’ service catalog API
Network policies Allows you to create rules on permitted connections and services. Requires a CNI plugin. Prevents unauthorized access, improves security, segregates namespaces. Weave Net
Calico
Authorization integration Enables an API level integration into the Kubernetes auth flow. Uses existing SSO to reduce the number of accounts and to centralize account management. Can integrate with almost any auth provider. Requires custom work
Image scanning Automates the scanning of vulnerabilities in your container images. Implemented at the CI stage of your pipeline. Because CVEs always happen. Docker
Snyk
Twistlock
Sonatype
Aqua Security
Log aggregation Brings all the logs from your application into a one searchable place. Logs are the best source of information on what went wrong. Fluentd or ELK 
(Elasticsearch, Logstash, Kibana) stack are good bets for rolling your own.
Posted in Information Technology

How to Use Your Own Domain to Access an AWS-Hosted Website

If you have had a domain name parked for a while and want to put it to better use, this post explains my experience in doing so.

Since my idea was to create a very simple website with static content, I decided to use an AWS S3 bucket. AWS documentation is good so I will not repeat the steps described there.

Creating a Zone Through Route 53

The purpose of this post is to clarify how to use your own domain name to serve the website content by using Amazon Route 53. From the AWS website:

Amazon Route 53 is a highly available and scalable Domain Name System (DNS) web service.

The first step with Route 53 is to create a zone. A zone represents a collective configuration for a group of DNS servers. The DNS configuration for a zone is stored in a zone file. The zone name must be the same as the corresponding domain name that, in turn, must also be the same as the name of the S3 bucket containing the website files.

In order to create the zone, there are two options: one is to import the zone file of the current DNS service provider and the other is to create the resource records manually.

However you do it, it is very important to export the zone file of the current DNS provider as it may be an invaluable reference. In my case, I had an email address associated to my domain and, after migrating to Route 53, I stopped getting emails. It was only after checking the exported zone file that I noticed that the MX record was missing in the Route 53 zone.

Zone File Records

When creating the zone, Route 53 will automatically generate the SOA and NS records. SOA (Start of Authority) record designates the authoritative name server for the zone or, in other words, the primary master name server. NS (Name Server) designates a name server for the zone. In this case, Route 53 generates 4 NS records corresponding to 4 different name servers (including the authoritative name server).

In addition, it is necessary to create an A record to map the domain name to the S3 bucket containing the website. Normally, an A record maps a domain names to an IPv4 address. However, Route 53 provides an extension to the standard DNS configuration that allows the creation of A records of type alias. When creating such a record, Route 53 gives you a list of the available AWS resources that can be mapped. For instance, my A record named “berronsolutions.co.uk” can be mapped to the S3 bucket with the same name.

It is also worth noticing that CNAME records cannot be used in the usual way. For instance, in order to point the subdomain “www.berronsolutions.co.uk” to the bucket with the website, it is necessary to:

  1. create a new bucket called “www.berronsolutions.co.uk” configured to redirect requests to the bucket “berronsolutions.co.uk”
  2. create an A record of type alias named “www.berronsolutions.co.uk” and pointing to the domain “berronsolutions.co.uk”

Name Servers Configuration

The final step in this process is to change the configuration of the current DNS provider to select as name servers the ones corresponding to the zone created in Route 53. After that, it took a few minutes for the new website to be available on the URL berronsolutions.co.uk.

My domain name was registered with GoDaddy and it was an easy task to export the zone file and change the name servers configuration through their website.

Finally, with the command “host”, it is possible to query the DNS information associated to a domain:

host -a berronsolutions.co.uk
Trying "berronsolutions.co.uk" ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58122 ;; flags: qr rd ra; QUERY: 1, ANSWER: 7, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;berronsolutions.co.uk. INANY ;; ANSWER SECTION: berronsolutions.co.uk.4INA52.218.105.52 berronsolutions.co.uk.21599INNSns-1063.awsdns-04.org. berronsolutions.co.uk.21599INNSns-1605.awsdns-08.co.uk. berronsolutions.co.uk.21599INNSns-219.awsdns-27.com. berronsolutions.co.uk.21599INNSns-878.awsdns-45.net. berronsolutions.co.uk.899INSOAns-219.awsdns-27.com. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400 berronsolutions.co.uk.599INMX0 berronsolutions-co-uk.mail.protection.outlook.com.

You can see the four NS records corresponding to the four name servers, with “ns-219.awsdns-27.com” being the master. There is also an A record to map the domain name to the S3 bucket IP.

By the way, if we had not wanted to go through the trouble of configuring our own domain name (or maybe we had not had one available), we could have used the endpoint provided by AWS.

Posted in Information Technology

Deploy & scale your application on AWS with Docker Swarm  

 

In this guide we will look at how to provision a set of 16 EC2 instances on AWS (Amazon Web Services) and then deploy an application with Docker Swarm services.

What the guide covers

  • Creating 16 Ubuntu 16.04 nodes in the EC2 console
  • An automated Docker installation
  • Automatic swarm uplinks
  • Deploying an application creating 16 replicas
  • Cleaning-up the AWS EC2 instances

Use case: distributed hash calculations (for cloud mining)

  • We join our nodes into crowd-sourced pool of processing power
  • Our nodes will calculate CPU-intensive hashes
  • We’ll get paid a small dividend for our computing power and time
  • Docker Swarm’s service function will handle the orchestration for us

A single node has a limited rate of calculating hashes, so we can increase that rate by joining many nodes together.

The Video

Cloudinit hacks

Most cloud providers give you an opportunity to run a custom script when your node is provisioned. The script is injected through a process called cloudinit

One hack I use in the scripts is to have the nodes reach out to an external website to find their public IP address. This is then passed into the docker swarm join call.

site=$(curl -s https://api.ipify.org/?format=text); \
 docker swarm join --advertise-addr $site   \
 --token SWMTKN-1-2nle9d1yoocuhtchkx9m1uba0xs8uwwquj1dq1v5ipjgp4fka5-aabs7ghllav8g7wjbv62zz3tp  \
 172.31.62.216:2377

The second hack I used was to automatically rename the cloud node with a suffix. Here’s the script I used:

export original=$(cat /etc/hostname)
sudo hostname $original-alexellisio
echo $original-alexellisio | sudo tee /etc/hostname

Docker has a new solution for provisioning infrastructure on AWS called Docker for AWS. You can find out more about the beta program here: docker.com/aws

Gists:

Here are the gists that I used in the video:

This gist also contains some benchmarks of various cloud instances from other providers.

Posted in Information Technology

Docker and PHP Best practice

 

From a DevOps point of view, the importance of a well-architected solution, with proper separation of responsibilities, is fundamental for the long-term success of any application. This case we are presenting today is a very simplified example made to showcase the concept and to be easily understood, but it sets the base to scale it on your own as you gain confidence on this topic. We will make use of Elastic Compute Service (ECS), Server Load Balancer (SLB) and Virtual Private Cloud (VPC), all very common Alibaba Cloud services that you should be familiar with.

Containers and Running Services

When using Docker, like in our case today, one should never run more than one function per container. Running more than one defeats the whole purpose of using containers, as adding them doesn’t cost much in terms of resources. In my experience, as DevOps lead engineer, I saw too many projects made by others with supervisord managing multiple functions in a single container. This is considered an anti-pattern as makes it very hard to track, debug and scale them horizontally. Please notice that I’m using the word function, not process. The official Docker documentation has moved away from saying one “process” to instead recommending one “concern” or “function” per container.

In today’s small example we are showing how to separate the responsibilities using a web service and an app service, as shown below:

1

When using PHP applications we have to make a choice about the web server to use, Apache being the one that would fit most cases. Apache is great in terms of modules, as you can use mod_php so Apache itself executes the PHP code directly. This means that you would only need one container and still be able to track and debug the application properly. It also helps in reducing the complexity of the deployment in websites that don’t experience a high concurrency of connections.

Our goal today is to build a highly-scalable project using Tengine allows us to separate the web server from the application codebase itself very simply.

What Is Tengine?

Tengine is, in a nutshell, Nginx with superpowers. This web server is everything you love about Nginx but with some neat extra features like dynamic module loading (loading modules without recompiling), unbuffered request proxy forwarding (saving precious disk I/Os), support for dynamic scripting language (Lua) for config files, and way more. You can have a look at the full list of features in the Tengine official site.

This web server has been an open source project since December 2011. Made by the Taobao team, it’s been used in sites like Taobao and Tmall, and used internally in Alibaba Cloud as a key part of their CDN’s Load Balancers.

As you can see, Tengine has been tested in some of the busiest websites in the world.

Preparing the Files

As we mentioned, we are planning to build a very simple but scalable project where we will separate the web server from the application codebase. This is achieved by running two containers, the web server listening to user requests and the PHP FPM interpreter as backend. Because this is a “best practices” type of article, we are setting up a Server Load Balancer to leave a playground afterwards to scale the whole thing. At the end, we will deploy everything using Terraform, a tool used to create, change and improve infrastructure in a predictable way.

docker-compose.yml

Given the maturity of the Docker Compose project, we are going to deploy this application by writing a docker-compose.yml file as shown below:

version: '3.7'

networks:
  webappnet:
    driver: bridge

services:
  app:
    image: php:7.3-fpm
    container_name: fpm
    networks:
    - webappnet
    restart: on-failure
    volumes:
    - ./index.php:/var/www/html/index.php
  web:
    image: roura/php:tengine-fpm
    container_name: tengine
    networks:
    - webappnet
    restart: on-failure
    ports:
    - 80:80
    volumes:
    - ./index.php:/var/www/html/index.php

As you can see, there are two services running in the network, app and web. The web service will pass all requests to the app one on port 9000, which is the one exposed by FPM by default. In the future, you can scale those two services independently and horizontally as needed.

index.php

Did I mention the app was going to be simple? You see, it has only one file, but enough to test that a PHP script is being rendered in the backend. Create the index.php next to the docker-compose.yml with the following content:

user-data.sh

This file will serve as the main template to bootstrap all services in the ECS instance. It basically installs all dependencies and creates the minimal files to start the containers.

#!/usr/bin/env bash

mkdir /var/docker

cat <<- 'EOF' > /var/docker/docker-compose.yml
${docker_compose}
EOF

cat <<- 'EOF' >/var/docker/index.php
${index_php}
EOF

apt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update && apt-get install -y docker-ce docker-compose
curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/bin/docker-compose

cd /var/docker && docker-compose up -d

main.tf

This is the file that will orchestrate it all. It creates a new VPC, a Server Load Balancer, and ECS without Internet IP and a Security Group locking it all down to the port 80 only. The file, named main.tf needs to be next to the others we just created and should look like the following:

provider "alicloud" {}

variable "app_name" {
  default = "webapp"
}

data "template_file" "docker_compose" {
  template = "${file("docker-compose.yml")}"
}

data "template_file" "index_php" {
  template = "${file("index.php")}"
}

data "template_file" "user_data" {
  template = "${file("user-data.sh")}"
  vars {
    docker_compose = "${data.template_file.docker_compose.rendered}"
    index_php = "${data.template_file.index_php.rendered}"
  }
}

data "alicloud_images" "default" {
  name_regex = "^ubuntu_16.*_64"
}

data "alicloud_instance_types" "default" {
  instance_type_family = "ecs.n4"
  cpu_core_count = 1
  memory_size = 2
}

resource "alicloud_vpc" "main" {
  cidr_block = "172.16.0.0/12"
}

data "alicloud_zones" "default" {
  available_disk_category = "cloud_efficiency"
  available_instance_type = "${data.alicloud_instance_types.default.instance_types.0.id}"
}

resource "alicloud_vswitch" "main" {
  availability_zone = "${data.alicloud_zones.default.zones.0.id}"
  cidr_block = "172.16.0.0/16"
  vpc_id = "${alicloud_vpc.main.id}"
}

resource "alicloud_security_group" "group" {
  name = "${var.app_name}-sg"
  vpc_id = "${alicloud_vpc.main.id}"
}

resource "alicloud_security_group_rule" "allow_http" {
  type = "ingress"
  ip_protocol = "tcp"
  nic_type = "intranet"
  policy = "accept"
  port_range = "80/80"
  priority = 1
  security_group_id = "${alicloud_security_group.group.id}"
  cidr_ip = "0.0.0.0/0"
}

resource "alicloud_security_group_rule" "egress" {
  type = "egress"
  ip_protocol = "tcp"
  nic_type = "intranet"
  policy = "accept"
  port_range = "80/80"
  priority = 1
  security_group_id = "${alicloud_security_group.group.id}"
  cidr_ip = "0.0.0.0/0"
}

resource "alicloud_slb" "main" {
  name = "${var.app_name}-slb"
  vswitch_id = "${alicloud_vswitch.main.id}"
  internet = true
}

resource "alicloud_slb_listener" "https" {
  load_balancer_id = "${alicloud_slb.main.id}"
  backend_port = 80
  frontend_port = 80
  health_check_connect_port = 80
  bandwidth = -1
  protocol = "http"
  sticky_session = "on"
  sticky_session_type = "insert"
  cookie = "webappslbcookie"
  cookie_timeout = 86400
}

resource "alicloud_slb_attachment" "main" {
  load_balancer_id = "${alicloud_slb.main.id}"
  instance_ids = [
    "${alicloud_instance.webapp.id}"
  ]
}

resource "alicloud_instance" "webapp" {
  instance_name = "${var.app_name}"
  image_id = "${data.alicloud_images.default.images.0.image_id}"
  instance_type = "${data.alicloud_instance_types.default.instance_types.0.id}"
  vswitch_id = "${alicloud_vswitch.main.id}"
  security_groups = [
    "${alicloud_security_group.group.id}"
  ]
  password = "Test1234!"
  user_data = "${data.template_file.user_data.rendered}"
}

output "slb_ip" {
  value = "${alicloud_slb.main.address}"
}

Putting Everything Together

Since we have all the files written, we are ready to go. Run terraform init && terraform apply and wait until all your infrastructure resources are created.

When everything finishes, you will see the output printing something like slb_ip = 47.xx.xx.164. That is the public IP of the Load Balancer. Copy it and paste it into your web browser. Ta-da! A screen like the following screenshot should show up:

2

Congratulations, you are a better cloud architect now!

Posted in Information Technology

Introduction to Kubernetes Security

Kubernetes is fundamentally a complex system with lots of different potential attack vectors aimed at data theft currency mining and other threats. Brice Fernandes started us off with a discussion on how to secure your operations to Kubernetes using GitOps best practices. Liz Rice then followed up on the current state of Kubernetes security-related features as well as best practices and other tips on how to secure your cluster.

GitOps Is an Operations Model for Kubernetes

According to Brice, Kubernetes clusters were traditionally accessed by developers directly, using the command line tool `kubectl`. There are of course many issues with having your development team directly accessing the cluster in this way. The biggest problem with this is that it is really hard to audit and track who did what, when.

GitOps eliminates this direct insecure access and instead provides a way for developers to safely access the cluster through a Git repository.

GitOps can be summarized as these two things:

  1. An operating model for Kubernetes and other cloud-native technologies, providing a set of best practices that unify deployment, management, and monitoring for containerized clusters and applications.
  2. A path towards a developer experience for managing applications; where end-to-end Git workflows are applied to both operations, and development.

gitops-kubernetes

The development team makes changes to applications through pull requests in the Git repository. Software deployment agents kept inside of the cluster are then responsible for applying those changes safely to the cluster. With deployment agents kept inside of the cluster, developers no longer need direct access. This also prevents credentials from being easily exploited through your CI system, where cluster secrets may be exposed as environment variables in custom scripts outside of the cluster’s trust domain.

deployment-agents-kubernetes.png

What You Need for GitOps

For GitOps workflows, these are the things you need:

  1. Your entire system described declaratively.
  2. The desired system state versioned-controlled in Git.
  3. Any changes to the desired state applied as version-controlled commits.
  4. Software agents that alert on divergence and synchronize the desired state in Git with a running cluster.

Why GitOps Is a More Secure Pipeline

As mentioned, CI/CD with GitOps addresses insecure pipelines by running a deployment agent within the cluster. It operates on a configuration Git repo, with its own credentials. The software agents compare and reconcile the desired state as expressed in the manifest files kept in Git against the actual state of the cluster.

In this way, cluster credentials don’t leak across the boundaries within your deployment pipeline. For example, your CI system can operate in a different security ‘zone’ rather than on the target cluster. Also, each pipeline component will only need a single RW credential. In addition, Git also provides you with exceptional auditing capabilities of who did what, and when and other security guarantees.

GitOps-pipeline.png

GitOps and Securing Your Git Repository

As you can see, GitOps is a more secure way to update deployments to Kubernetes, but it does mean that the burden of security has shifted on to Git itself.

The main areas in Git that you need to pay attention are:

  • User impersonation
  • Malicious user tampering with the repository’s history
  • Malicious user attacks on the Git platform
  • Historical attacks on Git clients

Introduction to Kubernetes Security

Next, Liz Rice explained all of the major attack surfaces for Kubernetes that you need to consider before running your cluster in production. Because Kubernetes is a complex system with many APIs, there are several different attack surfaces from which your deployments can be compromised.

The main areas you need to focus on is your Kubernetes configuration setup and your application images. Both of these need to be set up properly to ensure that these are locked down sufficiently so that attackers don’t find any weak spots.

Tesla Cloud Hacked by Cryptocurrency Mining Software

Several months ago, there was a famous attack on Tesla cloud where an attacker had installed cryptocurrency mining malware on their servers. The attackers got in because of exposed cluster admin credentials on the Kubernetes dashboard that was left open to the Internet after a fresh installation of Kubernetes.

But Liz explained that a lot of improvements have been made to out-of-the-box security for Kubernetes. For example, kubeadm, a popular installer no longer installs the kube dashboard by default. It also now makes many of the default settings more robust so they can’t be hacked.

However, Liz stressed that one of the most important things you can do is keep your Kubernetes version up to date.

What Do You Need to Secure?

Although most settings are now more robust after you’ve installed Kubernetes, you still need to lock down the Control Plane and you also need to ensure your application containers are secure.

Control Plane

  • API server
  • Etcd APIs
  • Kubelet APIs
  • Implement RBAC

Container Images

  • Limit your set of base images
  • Define the USER in containers and don’t run as root
  • Automate and use a vulnerability scanner
  • It’s good practice to use a private image registry
  • Pin dependencies for reproducible builds
  • Define network policy for Pods and containers
  • Manage secrets carefully

To research what settings need attention in your control plane, Liz suggests that you take a look at the guide put out by the Centre of Internet Security, CIS Benchmarks. You can also run the open-source tool, kube-bench to see how compliant and secure your cluster is.