Build Docker image with AWS CLI tools installed

Using Docker image with AWS CLI tools installed

docker@boot2docker:~$ docker pull sdevarapalli/aws-cli
Using default tag: latest
latest: Pulling from sdevarapalli/aws-cli

3d8673bd162a: Pull complete
da63d6cdd79e: Pull complete
13e98e81fd0b: Pull complete
6722a77327b6: Pull complete
6d930c14ca40: Pull complete
b3c4f1214f20: Pull complete
Digest: sha256:9e50b198a8909febe940b7fd702c7f92d9ff353e941140be06c7a9b9d38fd67a
Status: Downloaded newer image for sdevarapalli/aws-cli:latest
docker@boot2docker:~$
docker@boot2docker:~$
docker@boot2docker:~$
docker@boot2docker:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sdevarapalli/aws-cli latest ec15aa2e51a2 37 minutes ago 699.6 MB
docker@boot2docker:~$
docker@boot2docker:~$
docker@boot2docker:~$
docker@boot2docker:~$docker run -i -t -h aws-cli \
--env AWS_ACCESS_KEY_ID=REPLACE_WITH_ACCESS_KEY_ID \
--env AWS_SECRET_ACCESS_KEY=REPLACE_WITH_SECRET_ACCESS_KEY \
--env AWS_DEFAULT_REGION=us-east-1 \
sdevarapalli/aws-cli /bin/bash
[root@aws-cli /]# aws iam list-users
{
"Users": [
{
"UserName": "xyz",
"PasswordLastUsed": "1900-01-01T01:01:01Z",
"CreateDate": "1900-01-01T01:01:01Z",
"UserId": "1111111",
"Path": "/",
"Arn": "arn:aws:iam::111111:user/xyz"
}
]
}
[root@aws-cli /]#

Steps to build and publish image

Build Image

$ git clone https://github.com/sdevarapalli1/aws-cli.git
# cd aws-cli
$ docker build -t sdevarapalli/aws-cli:latest -t sdevarapalli/aws-cli:0.2 .
......
......
......
Successfully built ec15aa2e51a2
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sdevarapalli/aws-cli latest ec15aa2e51a2 2 minutes ago 699.6 MB

Log in and Publish Image to Docker Hub

docker@boot2docker:~$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username (sdevarapalli):
Password:
Login Succeeded


docker@boot2docker:~$ docker push sdevarapalli/aws-cli:latest
The push refers to a repository [docker.io/sdevarapalli/aws-cli]
6044067d6476: Pushed
4d04059a14fc: Pushed
2c54e224dec4: Pushed
f6ff5fe8484d: Pushed
e1ada7271bd0: Pushed
f59b7e59ceaa: Pushed
latest: digest: sha256:9e50b198a8909febe940b7fd702c7f92d9ff353e941140be06c7a9b9d38fd67a size: 1583
docker@boot2docker:~$
Advertisements

Boot2docker setup on Mac OS X

Boot2docker is officially deprecated. Use Docker for Mac if Mac OS X version is 10.10.3 or newer running on a 2010 or newer Mac, with Intel’s hardware support for MMU virtualization; use Docker Toolbox if software or hardware requirements are not met.

Check out Docker for Mac vs. Docker Toolbox to understand the differences.

  • Install Boot2Docker package (I have installed Boot2Docker-1.7.0.pkg)
  • Start instance sharing folder /users/sdevarapalli/learning/docker as “shared”
    ws@sdevarapalli:~> boot2docker --vbox-share="/users/sdevarapalli/learning/docker=shared" up
    
  • Set up environment variables
    ws@sdevarapalli:~> eval "$(boot2docker shellinit)"
    Writing /Users/sdevarapalli/.boot2docker/certs/boot2docker-vm/ca.pem
    Writing /Users/sdevarapalli/.boot2docker/certs/boot2docker-vm/cert.pem
    Writing /Users/sdevarapalli/.boot2docker/certs/boot2docker-vm/key.pem
    ws@sdevarapalli:~> env | grep -i docker
    DOCKER_HOST=tcp://192.168.59.103:2376
    DOCKER_TLS_VERIFY=1
    DOCKER_CERT_PATH=/Users/sdevarapalli/.boot2docker/certs/boot2docker-vm
    
  • Log in to the server
    ws@sdevarapalli:~> boot2docker ssh
     ## .
     ## ## ## ==
     ## ## ## ## ## ===
     /"""""""""""""""""\___/ ===
     ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
     \______ o __/
     \ \ __/
     \____\_______/
     _ _ ____ _ _
    | |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __
    | '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
    | |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ |
    |_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
    Boot2Docker version 1.12.0, build HEAD : e030bab - Fri Jul 29 00:29:14 UTC 2016
    Docker version 1.12.0, build 8eab29e
    docker@boot2docker:~$
    
  • To automatically mount the shared folder, add the script bootlocal.sh on the boot2docker host. This script gets executed on VM startup.
    docker@boot2docker:/mnt/sda1/var/lib/boot2docker$ cat bootlocal.sh
    sudo mkdir -p /mnt/shared
    sudo mount -t vboxsf shared /mnt/shared
    docker@boot2docker:/mnt/sda1/var/lib/boot2docker$
    
  • Commands to check status and shutdown:
    ws@sdevarapalli:~> boot2docker status
    running
    ws@ sdevarapalli:~> boot2docker stop
    

Using SSH-Agent With Screen

Carl’s excellent post describes how to set up Screen with ssh-agent so that when a new screen session is started, windows with names were set up and logged onto different servers automatically. It was not clear how to create the configuration file .screenrc_escP to me initially, but after a bit of trying the following steps worked:

  • open ~/.screenrc_escP in vi
  • type string “escape”
  • press tab key
  • press ctrl-v: holding the control key press the v key
  • press ctrl-p: holding the control key press the p key
  • type character p

In my terminal window character ctrl-p is in bold:

Screen Configuration File
.screenrc_escP

The escape sequence for the outer screen is ctrl-p instead of ctrl-a– to see the windows created in the outer screen type ctrl-p + ” — holding the control key press p, release the control key, press double quotes:

Screen Wrapper
Escape Sequence for Outer Screen is ctrl-p and Nested Screen is ctrl-a

I use ctrl-p at bash prompt to go to the previous command, so I chose ctrl-y as my escape character for the outer screen. After setting up config files and ssh-agent, starting a screen session created different windows and ssh connections opened to different servers.

Using Spring Handler Interceptors to Decouple Business Logic

Consider a Spring MVC application deployed in Tomcat servlet container. For each request, the following sequence of steps occur:

  • Tomcat gets the request and executes the configured chain of servlet filters
  • Spring Dispatcher Servlet receives the input request — assuming the request URL is configured to map to dispatcher servlet
  • Dispatcher Servlet maps the request URL to a handler using handler mapping– in other words, dispatcher servlet maps the request to an execution chain comprising a chain of Handler Interceptors and Controller. SpringUrlHandlerMapping can be used to map different URL patterns to different execution chains. For example, URL pattern /news/* could be mapped to interceptors AuthorizationHandlerInterceptor, RequestValidationHandlerInterceptor and NewsController.
  • View Resolver is used to resolve the view name returned by the controller and the view rendered

Below picture depicts the sequence of steps:

Spring Handler Interceptors
Spring Handler Interceptors

Let’s say that request processing logic for URL patterns /news/* and /premiumnews/* is exactly the same except that /premiumnews/* is accessible only for users with premium subscription. Logic to check if user is signed in and if user has premium subscription can be abstracted in PremiumSubscriptionValidatorHandlerInterceptor and included only in execution chain returned for /premiumnews/*.

<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="interceptors">
		<list>
			<ref bean="premiumSubscriptionValidatorHandlerInterceptor"></ref>
		</list>
	</property>
	<property name="mappings">
		<props>
			<prop key="/premiumnews/*">newsController</prop>
		</props>
	</property>
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<props>
			<prop key="/news/*">newsController</prop>
		</props>
	</property>
</bean>

Note that both the URL patterns are mapped to newsController and premiumSubscriptionValidatorHandlerInterceptor is included only in the mapping for /premiumnews/*

Another example: say that there are both web and mobile versions for news content, and web version displays modules “Popular on Facebook” and “News Pulse” — content for these modules are obtained by querying a web service. Since these modules are displayed on web version only, logic to query the web service can be abstracted into an interceptor and included in execution chain returned only for web requests.

Hope you understood how to decouple business logic using handler interceptors!

Change Log4j Levels at Runtime Using Openutils-Log4j

Log4j Version 1.3 has a ConfigurationServlet which can be used to view/modify the current log4j logger settings for a web application. Per the information on Log4j website version 1.3 has been abandoned:

log4j 1.3 abandoned
Log4j 1.3 Version Development Has Been Abandoned

Openutils-log4j includes the configuration servlet that provides a simple web interface for changing the log4j levels:

Log4j Control Console
Log4j Control Console

With the configuration below added in web.xml, control console will be accessible using URL pattern /chlog4j (e.g. http://localhost:8080/testwebapp/chlog4j):

  <servlet>
   <display-name>Log4j configuration Servlet</display-name>
   <servlet-name>log4j</servlet-name>
   <servlet-class>it.openutils.log4j.Log4jConfigurationServlet</servlet-class>
 </servlet>

  <servlet-mapping>
  	<servlet-name>log4j</servlet-name>
  	<url-pattern>/chlog4j/*</url-pattern>
  </servlet-mapping>

Dependency to be added in pom.xml:

<dependency>
  <groupId>net.sourceforge.openutils</groupId>
  <artifactId>openutils-log4j</artifactId>
  <version>2.0.3</version>
</dependency>

XPath Not Working

A seemingly simple XPath expression to modify some nodes in web.xml during maven build process using XMLTask from oops consultancy didn’t work. Article Little Back Corners nailed the issue — namespace declarations in xml file. I have used local-name() function to workaround the issue. Below is an example:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	
  <servlet>
   <display-name>Log4j configuration Servlet</display-name>
   <servlet-name>log4j</servlet-name>
   <servlet-class>it.openutils.log4j.Log4jConfigurationServlet</servlet-class>
 </servlet>

  <servlet-mapping>
  	<servlet-name>log4j</servlet-name>
  	<url-pattern>/chlog4j/*</url-pattern>
  </servlet-mapping>
 
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

XSLT to output servlet-class node value of servlet log4j:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">

<xsl:value-of select="/*[local-name()='web-app']/*[local-name()='servlet']/*[local-name()='servlet-name' and text()='log4j']/../*[local-name()='servlet-class']"></xsl:value-of>

</xsl:template>

</xsl:stylesheet>

Split a File Based on Line Pattern

csplit command can be used to split a file on line pattern. Below is a sample XML file and csplit command to create one file for each folder element:

<folder>
	folder1 - line 1
	folder1 - line 2
</folder>

<folder>
	folder2 - line 1
</folder>

<folder>
	folder3 - line 1
</folder>

<folder>
	folder4 - line 1
</folder>

csplit.exe --prefix=folder --suffix-format=%05d.txt --elide-empty-files folder.txt '/[:space:]*<\/folder>/+1' {*}
  • –prefix=folder: files created will have the filename prefix ‘folder’
  • –suffix-format=%05d.txt: files created will have suffix five digits (%05d) and ‘.txt’ (e.g. folder00000.txt)
  • –elide-empty-files: remove empty files (an empty file is created if there is an empty line after the last folder element)
  • –elide-empty-files: remove empty files (an empty file is created if there is an empty line after the last folder element)
  • ‘/[:space:]*/+1’: regular expression to match “zero or more spaces followed by ‘. +1 is used to output the matching line (i.e., also)
  • csplit - split file based on line pattern
    csplit - split file based on line pattern