├── .gitignore ├── Section 3 ├── 3.5_code │ ├── authorized_keys │ │ └── _gitignore │ ├── sshd-banner │ ├── supervisord.conf │ ├── license_accepter.sh │ └── Dockerfile ├── 3.6_code │ ├── authorized_keys │ │ └── _gitignore │ ├── sshd-banner │ ├── supervisord_vncserver.conf │ ├── 3.6_commands.txt │ ├── vncpass.sh │ ├── supervisord.conf │ ├── watchdog.sh │ ├── license_accepter.sh │ └── Dockerfile ├── 3.8_code │ ├── authorized_keys │ │ └── _gitignore │ ├── sshd-banner │ ├── supervisord.conf │ ├── license_accepter.sh │ └── Dockerfile ├── 3.9_code │ ├── authorized_keys │ │ └── _gitignore │ ├── sshd-banner │ ├── supervisord.conf │ ├── 3.9_commands.txt │ ├── gradle-server │ │ ├── Dockerfile │ │ └── gradle_downloader.sh │ ├── license_accepter.sh │ └── Dockerfile ├── 3.10_code │ └── 3.10_commands.txt ├── 3.1_code │ └── Dockerfile ├── 3.2_code │ └── Dockerfile ├── 3.3_code │ ├── Dockerfile │ └── license_accepter.sh └── 3.4_code │ └── Dockerfile ├── Section 2 └── Video 2.4_code │ ├── bmi │ ├── Gemfile │ └── bmi.rb │ └── Dockerfile ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS ### 2 | .DS_Store 3 | 4 | -------------------------------------------------------------------------------- /Section 3/3.5_code/authorized_keys/_gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /Section 3/3.6_code/authorized_keys/_gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /Section 3/3.8_code/authorized_keys/_gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /Section 3/3.9_code/authorized_keys/_gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /Section 2/Video 2.4_code/bmi/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'sinatra' 3 | gem 'sinatra-contrib' -------------------------------------------------------------------------------- /Section 2/Video 2.4_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:alpine 2 | 3 | EXPOSE 80 4 | 5 | ENV APP_HOME /app 6 | WORKDIR $APP_HOME 7 | ADD bmi $APP_HOME/ 8 | 9 | RUN bundle install 10 | CMD ["ruby", "bmi.rb"] 11 | -------------------------------------------------------------------------------- /Section 3/3.5_code/sshd-banner: -------------------------------------------------------------------------------- 1 | 2 | / \ _ __ __| |_ __ ___ (_) __| | 3 | / _ \ | '_ \ / _` | '__/ _ \| |/ _` | 4 | / ___ \| | | | (_| | | | (_) | | (_| | 5 | /_/ \_\_| |_|\__,_|_| \___/|_|\__,_| 6 | 7 | -------------------------------------------------------------------------------- /Section 3/3.6_code/sshd-banner: -------------------------------------------------------------------------------- 1 | 2 | / \ _ __ __| |_ __ ___ (_) __| | 3 | / _ \ | '_ \ / _` | '__/ _ \| |/ _` | 4 | / ___ \| | | | (_| | | | (_) | | (_| | 5 | /_/ \_\_| |_|\__,_|_| \___/|_|\__,_| 6 | 7 | -------------------------------------------------------------------------------- /Section 3/3.8_code/sshd-banner: -------------------------------------------------------------------------------- 1 | 2 | / \ _ __ __| |_ __ ___ (_) __| | 3 | / _ \ | '_ \ / _` | '__/ _ \| |/ _` | 4 | / ___ \| | | | (_| | | | (_) | | (_| | 5 | /_/ \_\_| |_|\__,_|_| \___/|_|\__,_| 6 | 7 | -------------------------------------------------------------------------------- /Section 3/3.9_code/sshd-banner: -------------------------------------------------------------------------------- 1 | 2 | / \ _ __ __| |_ __ ___ (_) __| | 3 | / _ \ | '_ \ / _` | '__/ _ \| |/ _` | 4 | / ___ \| | | | (_| | | | (_) | | (_| | 5 | /_/ \_\_| |_|\__,_|_| \___/|_|\__,_| 6 | 7 | -------------------------------------------------------------------------------- /Section 3/3.10_code/3.10_commands.txt: -------------------------------------------------------------------------------- 1 | docker run -it --rm -v $(pwd)/sdk:/sdk android-sdk bash -c 'cp -a $ANDROID_HOME/. /sdk' 2 | docker run -it -v $(pwd)/sdk:/opt/android-sdk android-sdk /bin/bash 3 | sdkmanager --list | grep patcher 4 | sdkmanager "patcher;v4" 5 | -------------------------------------------------------------------------------- /Section 3/3.5_code/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon = true 3 | 4 | [include] 5 | files = /etc/supervisor/conf.d/*.conf 6 | 7 | [program:sshd] 8 | command = /usr/sbin/sshd -D 9 | stderr_logfile = /var/log/supervisord/sshd-stderr.log 10 | stdout_logfile = /var/log/supervisord/sshd-stdout.log 11 | -------------------------------------------------------------------------------- /Section 3/3.1_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 6 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 7 | 8 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 9 | -------------------------------------------------------------------------------- /Section 3/3.6_code/supervisord_vncserver.conf: -------------------------------------------------------------------------------- 1 | [program:vncserver] 2 | command = /usr/bin/vncserver 3 | stderr_logfile = /var/log/supervisord/vncserver-stderr.log 4 | stdout_logfile = /var/log/supervisord/vncserver-stdout.log 5 | 6 | [program:watchdog] 7 | command = /usr/local/bin/watchdog.sh 8 | stderr_logfile = /var/log/supervisord/watchdog-stderr.log 9 | stdout_logfile = /var/log/supervisord/watchdog-stdout.log 10 | -------------------------------------------------------------------------------- /Section 3/3.6_code/3.6_commands.txt: -------------------------------------------------------------------------------- 1 | docker build -t android-sdk-emu . 2 | docker run -d -p 2222:22 -p 5901:5901 android-sdk-emu 3 | sdkmanager --list 4 | sdkmanager "emulator" "platform-tools" "platforms;android-24" "system-images;android-24;default;armeabi-v7a" 5 | echo "no" | avdmanager create avd -n test -k "system-images;android-24;default;armeabi-v7a" 6 | avdmanager list avd 7 | emulator64-arm -avd test -noaudio -no-boot-anim -accel on -gpu swiftshader_indirect & 8 | -------------------------------------------------------------------------------- /Section 3/3.6_code/vncpass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | password="android" 4 | password_view_only="docker" 5 | 6 | /usr/bin/expect < calculate_bmi(weight, height) } 17 | json bmi 18 | end 19 | -------------------------------------------------------------------------------- /Section 3/3.6_code/watchdog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | log_file=/var/log/supervisord/watchdog-stdout.log 4 | 5 | function clean_up { 6 | echo "--------------------------------------------------" >> $log_file 7 | echo "Removing lock files..." >> $log_file 8 | rm -fv /tmp/.X*-lock >> $log_file 9 | rm -fv /tmp/.X11-unix/* >> $log_file 10 | echo "All lock files are removed!" >> $log_file 11 | echo "--------------------------------------------------" >> $log_file 12 | exit 0 13 | } 14 | 15 | trap clean_up SIGTERM 16 | 17 | while true; do 18 | sleep 1 19 | done 20 | -------------------------------------------------------------------------------- /Section 3/3.2_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 && \ 6 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 7 | apt-get install -y --no-install-recommends wget unzip 8 | 9 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 10 | 11 | ARG ANDROID_SDK_VERSION=4333796 12 | ENV ANDROID_HOME /opt/android-sdk 13 | RUN mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} && \ 14 | wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip && \ 15 | unzip *tools*linux*.zip && \ 16 | rm *tools*linux*.zip 17 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin 18 | -------------------------------------------------------------------------------- /Section 3/3.3_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 && \ 6 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 7 | apt-get install -y --no-install-recommends wget unzip 8 | 9 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 10 | 11 | ARG ANDROID_SDK_VERSION=4333796 12 | ENV ANDROID_HOME /opt/android-sdk 13 | RUN mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} && \ 14 | wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip && \ 15 | unzip *tools*linux*.zip && \ 16 | rm *tools*linux*.zip 17 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin 18 | 19 | ADD license_accepter.sh /opt/ 20 | RUN chmod +x /opt/license_accepter.sh && /opt/license_accepter.sh $ANDROID_HOME 21 | -------------------------------------------------------------------------------- /Section 3/3.4_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 && \ 6 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 7 | apt-get install -y --no-install-recommends wget unzip git 8 | 9 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 10 | 11 | ARG ANDROID_SDK_VERSION=4333796 12 | ENV ANDROID_HOME /opt/android-sdk 13 | RUN mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} && \ 14 | wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip && \ 15 | unzip *tools*linux*.zip && \ 16 | rm *tools*linux*.zip 17 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin 18 | 19 | ADD license_accepter.sh /opt/ 20 | RUN chmod +x /opt/license_accepter.sh && /opt/license_accepter.sh $ANDROID_HOME 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Section 3/3.9_code/3.9_commands.txt: -------------------------------------------------------------------------------- 1 | # build the gradle mirror server image 2 | docker build --build-arg GRADLE_DOWNLOAD_AMOUNT=0 -t gradle-server gradle-server 3 | # launch a gradle mirror server container 4 | docker run -d -p 80:80 -p 443:443 -v $(pwd)/gradle-server/distributions:/var/www/gradle.org/public_html/distributions --name gradle-server gradle-server 5 | # access it by: 6 | http://localhost/distributions/ 7 | 8 | # launch an Android SDK container 9 | docker run -d -p 2222:22 -v $(pwd)/gradle/caches:/root/.gradle/caches --name android-sdk android-sdk 10 | # copy the SSL certificate from gradle server container to host machine 11 | docker cp gradle-server:/etc/apache2/ssl/apache.crt apache.crt 12 | # copy the SSL certificate from host machine to AndroidSDK container 13 | docker cp apache.crt android-sdk:/home/apache.crt 14 | # add self-signed SSL certificate to Java keystore 15 | docker exec -it android-sdk bash -c '$JAVA_HOME/bin/keytool -import -trustcacerts -file /home/apache.crt -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -noprompt' 16 | # map gradle services domain to your local IP 17 | docker exec -it android-sdk bash -c 'echo "[YOUR_HOST_IP_ADDRESS_FOR_GRADLE_CONTAINER] services.gradle.org" >> /etc/hosts' 18 | -------------------------------------------------------------------------------- /Section 3/3.9_code/gradle-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update -y && \ 4 | apt-get install -y wget 5 | 6 | ARG GRADLE_DOWNLOAD_AMOUNT=14 7 | ENV GRADLE_DIST /var/www/gradle.org/public_html/distributions 8 | ADD gradle_downloader.sh $GRADLE_DIST/ 9 | RUN apt-get install -y apache2 && \ 10 | sed -i 's%\(^\s*DocumentRoot\s*\).*%\1/var/www/gradle.org/public_html%g' /etc/apache2/sites-available/000-default.conf && \ 11 | echo "\n\n Options Indexes FollowSymLinks\n\n" >> /etc/apache2/apache2.conf && \ 12 | a2enmod ssl && \ 13 | mkdir /etc/apache2/ssl && \ 14 | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/apache2/ssl/apache.key -out /etc/apache2/ssl/apache.crt -subj "/C=DE/ST=Berlin/L=Berlin/CN=services.gradle.org" && \ 15 | sed -i 's%\(^\s*DocumentRoot\s*\).*%\1/var/www/gradle.org/public_html%g' /etc/apache2/sites-available/default-ssl.conf && \ 16 | sed -i 's%\(^\s*SSLCertificateFile\s*\).*%\1/etc/apache2/ssl/apache.crt%g' /etc/apache2/sites-available/default-ssl.conf && \ 17 | sed -i 's%\(^\s*SSLCertificateKeyFile\s*\).*%\1/etc/apache2/ssl/apache.key%g' /etc/apache2/sites-available/default-ssl.conf && \ 18 | a2ensite default-ssl.conf && \ 19 | chmod +x $GRADLE_DIST/gradle_downloader.sh && \ 20 | $GRADLE_DIST/gradle_downloader.sh $GRADLE_DIST $GRADLE_DOWNLOAD_AMOUNT 21 | EXPOSE 80 443 22 | CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"] 23 | -------------------------------------------------------------------------------- /Section 3/3.9_code/gradle-server/gradle_downloader.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check_and_set_parameters() { 4 | if [ "$#" -lt 1 ]; then 5 | echo "Missing parameter for download directory" 6 | exit 1 7 | elif [ "$#" -lt 2 ]; then 8 | DOWNLOAD_AMOUNT=65535 9 | fi 10 | DOWNLOAD_DIRECTORY=$1 11 | [ -z $DOWNLOAD_AMOUNT ] && DOWNLOAD_AMOUNT=$2 12 | } 13 | 14 | check_installation_of_wget() { 15 | which wget > /dev/null 2>&1 16 | if [ $? -ne 0 ]; then 17 | echo "wget is not installed" 18 | exit 1 19 | fi 20 | } 21 | 22 | download_from_link_to_dir() { 23 | local link=$1 24 | local directory=$2 25 | echo "--------------------------------------------------" 26 | echo $link 27 | local file="$directory/${link##*/}" 28 | if [ -f $file ]; then 29 | echo "File already exists, skip downloading." 30 | else 31 | echo "Start to download Gradle distribution..." 32 | wget -q --show-progress -P $directory $link 33 | printf "\n" 34 | fi 35 | } 36 | 37 | parse_gradle_distributions_links_and_download() { 38 | local url="https://services.gradle.org/distributions/" 39 | local links=(`wget -q -O- $url | grep -o "\".*distributions.*all\.zip\"" | grep -v "rc\|milestone" | sed "s/\"//g" | sed "s/.*distributions/https:\/\/services.gradle.org\/distributions/g"`) 40 | local downloaded=0 41 | for i in "${!links[@]}"; do 42 | [ $i -eq $DOWNLOAD_AMOUNT ] && break 43 | download_from_link_to_dir ${links[i]} $DOWNLOAD_DIRECTORY 44 | downloaded=$((downloaded+1)) 45 | done 46 | echo "$downloaded Gradle distributions have been downloaded." 47 | echo "--------------------------------------------------" 48 | } 49 | 50 | check_and_set_parameters "$@" 51 | check_installation_of_wget 52 | parse_gradle_distributions_links_and_download -------------------------------------------------------------------------------- /Section 3/3.3_code/license_accepter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check_android_home() { 4 | if [ "$#" -lt 1 ]; then 5 | if [ -z "${ANDROID_HOME}" ]; then 6 | echo "Please either set ANDROID_HOME environment variable, or pass ANDROID_HOME directory as a parameter" 7 | exit 1 8 | else 9 | ANDROID_HOME="${ANDROID_HOME}" 10 | fi 11 | else 12 | ANDROID_HOME=$1 13 | fi 14 | echo "ANDROID_HOME is at $ANDROID_HOME" 15 | } 16 | 17 | accept_all_android_licenses() { 18 | ANDROID_LICENSES="$ANDROID_HOME/licenses" 19 | if [ ! -d $ANDROID_LICENSES ]; then 20 | echo "Android licenses directory doesn't exist, creating one..." 21 | mkdir -p $ANDROID_LICENSES 22 | fi 23 | 24 | accept_license_of android-googletv-license 601085b94cd77f0b54ff86406957099ebe79c4d6 25 | accept_license_of android-sdk-license 8933bad161af4178b1185d1a37fbf41ea5269c55 26 | accept_license_of android-sdk-license d56f5187479451eabf01fb78af6dfcb131a6481e 27 | accept_license_of android-sdk-license 24333f8a63b6825ea9c5514f83c2829b004d1fee 28 | accept_license_of android-sdk-preview-license 84831b9409646a918e30573bab4c9c91346d8abd 29 | accept_license_of android-sdk-preview-license 504667f4c0de7af1a06de9f4b1727b84351f2910 30 | accept_license_of google-gdk-license 33b6a2b64607f11b759f320ef9dff4ae5c47d97a 31 | accept_license_of intel-android-extra-license d975f751698a77b662f1254ddbeed3901e976f5a 32 | } 33 | 34 | accept_license_of() { 35 | local license=$1 36 | local content=$2 37 | local file=$ANDROID_LICENSES/$license 38 | if [ -f $file ]; then 39 | if grep -q "^$content$" $file; then 40 | echo "$license: $content has been accepted already" 41 | else 42 | echo "Accepting $license: $content ..." 43 | echo -e $content >> $file 44 | fi 45 | else 46 | echo "Accepting $license: $content ..." 47 | echo -e $content > $file 48 | fi 49 | } 50 | 51 | check_android_home "$@" 52 | accept_all_android_licenses 53 | -------------------------------------------------------------------------------- /Section 3/3.5_code/license_accepter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check_android_home() { 4 | if [ "$#" -lt 1 ]; then 5 | if [ -z "${ANDROID_HOME}" ]; then 6 | echo "Please either set ANDROID_HOME environment variable, or pass ANDROID_HOME directory as a parameter" 7 | exit 1 8 | else 9 | ANDROID_HOME="${ANDROID_HOME}" 10 | fi 11 | else 12 | ANDROID_HOME=$1 13 | fi 14 | echo "ANDROID_HOME is at $ANDROID_HOME" 15 | } 16 | 17 | accept_all_android_licenses() { 18 | ANDROID_LICENSES="$ANDROID_HOME/licenses" 19 | if [ ! -d $ANDROID_LICENSES ]; then 20 | echo "Android licenses directory doesn't exist, creating one..." 21 | mkdir -p $ANDROID_LICENSES 22 | fi 23 | 24 | accept_license_of android-googletv-license 601085b94cd77f0b54ff86406957099ebe79c4d6 25 | accept_license_of android-sdk-license 8933bad161af4178b1185d1a37fbf41ea5269c55 26 | accept_license_of android-sdk-license d56f5187479451eabf01fb78af6dfcb131a6481e 27 | accept_license_of android-sdk-license 24333f8a63b6825ea9c5514f83c2829b004d1fee 28 | accept_license_of android-sdk-preview-license 84831b9409646a918e30573bab4c9c91346d8abd 29 | accept_license_of android-sdk-preview-license 504667f4c0de7af1a06de9f4b1727b84351f2910 30 | accept_license_of google-gdk-license 33b6a2b64607f11b759f320ef9dff4ae5c47d97a 31 | accept_license_of intel-android-extra-license d975f751698a77b662f1254ddbeed3901e976f5a 32 | } 33 | 34 | accept_license_of() { 35 | local license=$1 36 | local content=$2 37 | local file=$ANDROID_LICENSES/$license 38 | if [ -f $file ]; then 39 | if grep -q "^$content$" $file; then 40 | echo "$license: $content has been accepted already" 41 | else 42 | echo "Accepting $license: $content ..." 43 | echo -e $content >> $file 44 | fi 45 | else 46 | echo "Accepting $license: $content ..." 47 | echo -e $content > $file 48 | fi 49 | } 50 | 51 | check_android_home "$@" 52 | accept_all_android_licenses 53 | -------------------------------------------------------------------------------- /Section 3/3.6_code/license_accepter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check_android_home() { 4 | if [ "$#" -lt 1 ]; then 5 | if [ -z "${ANDROID_HOME}" ]; then 6 | echo "Please either set ANDROID_HOME environment variable, or pass ANDROID_HOME directory as a parameter" 7 | exit 1 8 | else 9 | ANDROID_HOME="${ANDROID_HOME}" 10 | fi 11 | else 12 | ANDROID_HOME=$1 13 | fi 14 | echo "ANDROID_HOME is at $ANDROID_HOME" 15 | } 16 | 17 | accept_all_android_licenses() { 18 | ANDROID_LICENSES="$ANDROID_HOME/licenses" 19 | if [ ! -d $ANDROID_LICENSES ]; then 20 | echo "Android licenses directory doesn't exist, creating one..." 21 | mkdir -p $ANDROID_LICENSES 22 | fi 23 | 24 | accept_license_of android-googletv-license 601085b94cd77f0b54ff86406957099ebe79c4d6 25 | accept_license_of android-sdk-license 8933bad161af4178b1185d1a37fbf41ea5269c55 26 | accept_license_of android-sdk-license d56f5187479451eabf01fb78af6dfcb131a6481e 27 | accept_license_of android-sdk-license 24333f8a63b6825ea9c5514f83c2829b004d1fee 28 | accept_license_of android-sdk-preview-license 84831b9409646a918e30573bab4c9c91346d8abd 29 | accept_license_of android-sdk-preview-license 504667f4c0de7af1a06de9f4b1727b84351f2910 30 | accept_license_of google-gdk-license 33b6a2b64607f11b759f320ef9dff4ae5c47d97a 31 | accept_license_of intel-android-extra-license d975f751698a77b662f1254ddbeed3901e976f5a 32 | } 33 | 34 | accept_license_of() { 35 | local license=$1 36 | local content=$2 37 | local file=$ANDROID_LICENSES/$license 38 | if [ -f $file ]; then 39 | if grep -q "^$content$" $file; then 40 | echo "$license: $content has been accepted already" 41 | else 42 | echo "Accepting $license: $content ..." 43 | echo -e $content >> $file 44 | fi 45 | else 46 | echo "Accepting $license: $content ..." 47 | echo -e $content > $file 48 | fi 49 | } 50 | 51 | check_android_home "$@" 52 | accept_all_android_licenses 53 | -------------------------------------------------------------------------------- /Section 3/3.8_code/license_accepter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check_android_home() { 4 | if [ "$#" -lt 1 ]; then 5 | if [ -z "${ANDROID_HOME}" ]; then 6 | echo "Please either set ANDROID_HOME environment variable, or pass ANDROID_HOME directory as a parameter" 7 | exit 1 8 | else 9 | ANDROID_HOME="${ANDROID_HOME}" 10 | fi 11 | else 12 | ANDROID_HOME=$1 13 | fi 14 | echo "ANDROID_HOME is at $ANDROID_HOME" 15 | } 16 | 17 | accept_all_android_licenses() { 18 | ANDROID_LICENSES="$ANDROID_HOME/licenses" 19 | if [ ! -d $ANDROID_LICENSES ]; then 20 | echo "Android licenses directory doesn't exist, creating one..." 21 | mkdir -p $ANDROID_LICENSES 22 | fi 23 | 24 | accept_license_of android-googletv-license 601085b94cd77f0b54ff86406957099ebe79c4d6 25 | accept_license_of android-sdk-license 8933bad161af4178b1185d1a37fbf41ea5269c55 26 | accept_license_of android-sdk-license d56f5187479451eabf01fb78af6dfcb131a6481e 27 | accept_license_of android-sdk-license 24333f8a63b6825ea9c5514f83c2829b004d1fee 28 | accept_license_of android-sdk-preview-license 84831b9409646a918e30573bab4c9c91346d8abd 29 | accept_license_of android-sdk-preview-license 504667f4c0de7af1a06de9f4b1727b84351f2910 30 | accept_license_of google-gdk-license 33b6a2b64607f11b759f320ef9dff4ae5c47d97a 31 | accept_license_of intel-android-extra-license d975f751698a77b662f1254ddbeed3901e976f5a 32 | } 33 | 34 | accept_license_of() { 35 | local license=$1 36 | local content=$2 37 | local file=$ANDROID_LICENSES/$license 38 | if [ -f $file ]; then 39 | if grep -q "^$content$" $file; then 40 | echo "$license: $content has been accepted already" 41 | else 42 | echo "Accepting $license: $content ..." 43 | echo -e $content >> $file 44 | fi 45 | else 46 | echo "Accepting $license: $content ..." 47 | echo -e $content > $file 48 | fi 49 | } 50 | 51 | check_android_home "$@" 52 | accept_all_android_licenses 53 | -------------------------------------------------------------------------------- /Section 3/3.9_code/license_accepter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | check_android_home() { 4 | if [ "$#" -lt 1 ]; then 5 | if [ -z "${ANDROID_HOME}" ]; then 6 | echo "Please either set ANDROID_HOME environment variable, or pass ANDROID_HOME directory as a parameter" 7 | exit 1 8 | else 9 | ANDROID_HOME="${ANDROID_HOME}" 10 | fi 11 | else 12 | ANDROID_HOME=$1 13 | fi 14 | echo "ANDROID_HOME is at $ANDROID_HOME" 15 | } 16 | 17 | accept_all_android_licenses() { 18 | ANDROID_LICENSES="$ANDROID_HOME/licenses" 19 | if [ ! -d $ANDROID_LICENSES ]; then 20 | echo "Android licenses directory doesn't exist, creating one..." 21 | mkdir -p $ANDROID_LICENSES 22 | fi 23 | 24 | accept_license_of android-googletv-license 601085b94cd77f0b54ff86406957099ebe79c4d6 25 | accept_license_of android-sdk-license 8933bad161af4178b1185d1a37fbf41ea5269c55 26 | accept_license_of android-sdk-license d56f5187479451eabf01fb78af6dfcb131a6481e 27 | accept_license_of android-sdk-license 24333f8a63b6825ea9c5514f83c2829b004d1fee 28 | accept_license_of android-sdk-preview-license 84831b9409646a918e30573bab4c9c91346d8abd 29 | accept_license_of android-sdk-preview-license 504667f4c0de7af1a06de9f4b1727b84351f2910 30 | accept_license_of google-gdk-license 33b6a2b64607f11b759f320ef9dff4ae5c47d97a 31 | accept_license_of intel-android-extra-license d975f751698a77b662f1254ddbeed3901e976f5a 32 | } 33 | 34 | accept_license_of() { 35 | local license=$1 36 | local content=$2 37 | local file=$ANDROID_LICENSES/$license 38 | if [ -f $file ]; then 39 | if grep -q "^$content$" $file; then 40 | echo "$license: $content has been accepted already" 41 | else 42 | echo "Accepting $license: $content ..." 43 | echo -e $content >> $file 44 | fi 45 | else 46 | echo "Accepting $license: $content ..." 47 | echo -e $content > $file 48 | fi 49 | } 50 | 51 | check_android_home "$@" 52 | accept_all_android_licenses 53 | -------------------------------------------------------------------------------- /Section 3/3.5_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 && \ 6 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 7 | apt-get install -y --no-install-recommends wget unzip git 8 | 9 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 10 | 11 | ARG ANDROID_SDK_VERSION=4333796 12 | ENV ANDROID_HOME /opt/android-sdk 13 | RUN mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} && \ 14 | wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip && \ 15 | unzip *tools*linux*.zip && \ 16 | rm *tools*linux*.zip 17 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin 18 | 19 | ADD license_accepter.sh /opt/ 20 | RUN chmod +x /opt/license_accepter.sh && /opt/license_accepter.sh $ANDROID_HOME 21 | 22 | EXPOSE 22 23 | ADD sshd-banner /etc/ssh/ 24 | ADD authorized_keys /tmp/ 25 | RUN apt-get update -y && \ 26 | apt-get install -y --no-install-recommends openssh-server supervisor locales && \ 27 | mkdir -p /var/run/sshd /var/log/supervisord && \ 28 | locale-gen en en_US en_US.UTF-8 && \ 29 | apt-get remove -y locales && apt-get autoremove -y && \ 30 | FILE_SSHD_CONFIG="/etc/ssh/sshd_config" && \ 31 | echo "\nBanner /etc/ssh/sshd-banner" >> $FILE_SSHD_CONFIG && \ 32 | echo "\nPermitUserEnvironment=yes" >> $FILE_SSHD_CONFIG && \ 33 | ssh-keygen -q -N "" -f /root/.ssh/id_rsa && \ 34 | FILE_SSH_ENV="/root/.ssh/environment" && \ 35 | touch $FILE_SSH_ENV && chmod 600 $FILE_SSH_ENV && \ 36 | printenv | grep "JAVA_HOME\|ANDROID_HOME\|PATH" >> $FILE_SSH_ENV && \ 37 | FILE_AUTH_KEYS="/root/.ssh/authorized_keys" && \ 38 | touch $FILE_AUTH_KEYS && chmod 600 $FILE_AUTH_KEYS && \ 39 | for file in /tmp/*.pub; \ 40 | do if [ -f "$file" ]; then echo "\n" >> $FILE_AUTH_KEYS && cat $file >> $FILE_AUTH_KEYS && echo "\n" >> $FILE_AUTH_KEYS; fi; \ 41 | done && \ 42 | (rm /tmp/*.pub 2> /dev/null || true) 43 | 44 | ADD supervisord.conf /etc/supervisor/conf.d/ 45 | CMD ["/usr/bin/supervisord"] -------------------------------------------------------------------------------- /Section 3/3.8_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 && \ 6 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 7 | apt-get install -y --no-install-recommends wget unzip git && \ 8 | apt-get install -y --no-install-recommends qt5-default 9 | 10 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 11 | ENV _JAVA_OPTIONS -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 12 | 13 | ARG ANDROID_SDK_VERSION=4333796 14 | ENV ANDROID_HOME /opt/android-sdk 15 | RUN mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} && \ 16 | wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip && \ 17 | unzip *tools*linux*.zip && \ 18 | rm *tools*linux*.zip 19 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/emulator 20 | ENV LD_LIBRARY_PATH ${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/qt/lib 21 | 22 | ADD license_accepter.sh /opt/ 23 | RUN chmod +x /opt/license_accepter.sh && /opt/license_accepter.sh $ANDROID_HOME 24 | 25 | EXPOSE 22 26 | ADD sshd-banner /etc/ssh/ 27 | ADD authorized_keys /tmp/ 28 | RUN apt-get update -y && \ 29 | apt-get install -y --no-install-recommends openssh-server supervisor locales && \ 30 | mkdir -p /var/run/sshd /var/log/supervisord && \ 31 | locale-gen en en_US en_US.UTF-8 && \ 32 | apt-get remove -y locales && apt-get autoremove -y && \ 33 | FILE_SSHD_CONFIG="/etc/ssh/sshd_config" && \ 34 | echo "\nBanner /etc/ssh/sshd-banner" >> $FILE_SSHD_CONFIG && \ 35 | echo "\nPermitUserEnvironment=yes" >> $FILE_SSHD_CONFIG && \ 36 | ssh-keygen -q -N "" -f /root/.ssh/id_rsa && \ 37 | FILE_SSH_ENV="/root/.ssh/environment" && \ 38 | touch $FILE_SSH_ENV && chmod 600 $FILE_SSH_ENV && \ 39 | printenv | grep "JAVA_HOME\|_JAVA_OPTIONS\|ANDROID_HOME\|PATH\|LD_LIBRARY_PATH" >> $FILE_SSH_ENV && \ 40 | FILE_AUTH_KEYS="/root/.ssh/authorized_keys" && \ 41 | touch $FILE_AUTH_KEYS && chmod 600 $FILE_AUTH_KEYS && \ 42 | for file in /tmp/*.pub; \ 43 | do if [ -f "$file" ]; then echo "\n" >> $FILE_AUTH_KEYS && cat $file >> $FILE_AUTH_KEYS && echo "\n" >> $FILE_AUTH_KEYS; fi; \ 44 | done && \ 45 | (rm /tmp/*.pub 2> /dev/null || true) 46 | 47 | # setup adb server 48 | EXPOSE 5037 49 | 50 | ADD supervisord.conf /etc/supervisor/conf.d/ 51 | CMD ["/usr/bin/supervisord"] 52 | -------------------------------------------------------------------------------- /Section 3/3.9_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 && \ 6 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 7 | apt-get install -y --no-install-recommends wget unzip git && \ 8 | apt-get install -y --no-install-recommends qt5-default 9 | 10 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 11 | ENV _JAVA_OPTIONS -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 12 | 13 | ARG ANDROID_SDK_VERSION=4333796 14 | ENV ANDROID_HOME /opt/android-sdk 15 | RUN mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} && \ 16 | wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip && \ 17 | unzip *tools*linux*.zip && \ 18 | rm *tools*linux*.zip 19 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/emulator 20 | ENV LD_LIBRARY_PATH ${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/qt/lib 21 | 22 | ADD license_accepter.sh /opt/ 23 | RUN chmod +x /opt/license_accepter.sh && /opt/license_accepter.sh $ANDROID_HOME 24 | 25 | EXPOSE 22 26 | ADD sshd-banner /etc/ssh/ 27 | ADD authorized_keys /tmp/ 28 | RUN apt-get update -y && \ 29 | apt-get install -y --no-install-recommends openssh-server supervisor locales && \ 30 | mkdir -p /var/run/sshd /var/log/supervisord && \ 31 | locale-gen en en_US en_US.UTF-8 && \ 32 | apt-get remove -y locales && apt-get autoremove -y && \ 33 | FILE_SSHD_CONFIG="/etc/ssh/sshd_config" && \ 34 | echo "\nBanner /etc/ssh/sshd-banner" >> $FILE_SSHD_CONFIG && \ 35 | echo "\nPermitUserEnvironment=yes" >> $FILE_SSHD_CONFIG && \ 36 | ssh-keygen -q -N "" -f /root/.ssh/id_rsa && \ 37 | FILE_SSH_ENV="/root/.ssh/environment" && \ 38 | touch $FILE_SSH_ENV && chmod 600 $FILE_SSH_ENV && \ 39 | printenv | grep "JAVA_HOME\|_JAVA_OPTIONS\|ANDROID_HOME\|PATH\|LD_LIBRARY_PATH" >> $FILE_SSH_ENV && \ 40 | FILE_AUTH_KEYS="/root/.ssh/authorized_keys" && \ 41 | touch $FILE_AUTH_KEYS && chmod 600 $FILE_AUTH_KEYS && \ 42 | for file in /tmp/*.pub; \ 43 | do if [ -f "$file" ]; then echo "\n" >> $FILE_AUTH_KEYS && cat $file >> $FILE_AUTH_KEYS && echo "\n" >> $FILE_AUTH_KEYS; fi; \ 44 | done && \ 45 | (rm /tmp/*.pub 2> /dev/null || true) 46 | 47 | # setup adb server 48 | EXPOSE 5037 49 | 50 | ADD supervisord.conf /etc/supervisor/conf.d/ 51 | CMD ["/usr/bin/supervisord"] 52 | -------------------------------------------------------------------------------- /Section 3/3.6_code/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update -y && \ 5 | apt-get install -y --no-install-recommends libncurses5:i386 libc6:i386 libstdc++6:i386 lib32gcc1 lib32ncurses5 lib32z1 zlib1g:i386 && \ 6 | apt-get install -y --no-install-recommends openjdk-8-jdk && \ 7 | apt-get install -y --no-install-recommends wget unzip git && \ 8 | apt-get install -y --no-install-recommends qt5-default 9 | 10 | ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 11 | 12 | ARG ANDROID_SDK_VERSION=4333796 13 | ENV ANDROID_HOME /opt/android-sdk 14 | RUN mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} && \ 15 | wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip && \ 16 | unzip *tools*linux*.zip && \ 17 | rm *tools*linux*.zip 18 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/emulator 19 | ENV LD_LIBRARY_PATH ${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/qt/lib 20 | 21 | ADD license_accepter.sh /opt/ 22 | RUN chmod +x /opt/license_accepter.sh && /opt/license_accepter.sh $ANDROID_HOME 23 | 24 | EXPOSE 22 25 | ADD sshd-banner /etc/ssh/ 26 | ADD authorized_keys /tmp/ 27 | RUN apt-get update -y && \ 28 | apt-get install -y --no-install-recommends openssh-server supervisor locales && \ 29 | mkdir -p /var/run/sshd /var/log/supervisord && \ 30 | locale-gen en en_US en_US.UTF-8 && \ 31 | apt-get remove -y locales && apt-get autoremove -y && \ 32 | FILE_SSHD_CONFIG="/etc/ssh/sshd_config" && \ 33 | echo "\nBanner /etc/ssh/sshd-banner" >> $FILE_SSHD_CONFIG && \ 34 | echo "\nPermitUserEnvironment=yes" >> $FILE_SSHD_CONFIG && \ 35 | ssh-keygen -q -N "" -f /root/.ssh/id_rsa && \ 36 | FILE_SSH_ENV="/root/.ssh/environment" && \ 37 | touch $FILE_SSH_ENV && chmod 600 $FILE_SSH_ENV && \ 38 | printenv | grep "JAVA_HOME\|ANDROID_HOME\|PATH\|LD_LIBRARY_PATH" >> $FILE_SSH_ENV && \ 39 | FILE_AUTH_KEYS="/root/.ssh/authorized_keys" && \ 40 | touch $FILE_AUTH_KEYS && chmod 600 $FILE_AUTH_KEYS && \ 41 | for file in /tmp/*.pub; \ 42 | do if [ -f "$file" ]; then echo "\n" >> $FILE_AUTH_KEYS && cat $file >> $FILE_AUTH_KEYS && echo "\n" >> $FILE_AUTH_KEYS; fi; \ 43 | done && \ 44 | (rm /tmp/*.pub 2> /dev/null || true) 45 | 46 | # setup adb server 47 | EXPOSE 5037 48 | 49 | ADD supervisord.conf /etc/supervisor/conf.d/ 50 | CMD ["/usr/bin/supervisord"] 51 | 52 | # install and configure VNC server 53 | ENV USER root 54 | ENV DISPLAY :1 55 | EXPOSE 5901 56 | ADD vncpass.sh /tmp/ 57 | ADD watchdog.sh /usr/local/bin/ 58 | ADD supervisord_vncserver.conf /etc/supervisor/conf.d/ 59 | RUN apt-get update -y && \ 60 | DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends xfce4 xfce4-goodies xfonts-base dbus-x11 tightvncserver expect && \ 61 | chmod +x /tmp/vncpass.sh; sync && \ 62 | /tmp/vncpass.sh && \ 63 | rm /tmp/vncpass.sh && \ 64 | apt-get remove -y expect && apt-get autoremove -y && \ 65 | FILE_SSH_ENV="/root/.ssh/environment" && \ 66 | echo "DISPLAY=:1" >> $FILE_SSH_ENV 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-Continuous-Integration-with-Docker-and-Jenkins 2 | This is the code repository for [Android Continuous Integration with Docker and Jenkins [Video]](https://prod.packtpub.com/in/application-development/android-continuous-integration-docker-and-jenkins-video), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish. 3 | 4 | ## About the Video Course 5 | As an Android developer, you feel a strong need for a hassle-free CI environment; moreover, you need a cloneable environment, especially for your UI tests, which need to be run on an Android “device". This course will show you how to create a fully functional CI using container technology; it lists all the problems you'll encounter and provides you with the corresponding solutions and detailed explanations. Later it will tell you how to setup scalable Jenkins nodes which enables parallel building, leaving you with no rework and no headaches at all. What if you have different hardware—maybe Linux machines or Mac computers? It works everywhere. You want your CI fast, stable, and lightweight, and preferably a free solution? No problem, you’ll be able to achieve your dream CI with Docker and scale it to all your systems by the end of this course. 6 | 7 |

What You Will Learn

8 |
9 |
17 | 18 | ## Instructions and Navigation 19 | ### Assumed Knowledge 20 | This course is ideal for Android developers working within large teams in an organisation as well as solo developers who want to kick off release builds quickly and consistently with great efficiency using Docker. It could also help DevOps engineers who need to build a flawless CI environment for their Android developers. No experience of Docker or Android is required, just bring your passion with you. 21 | 22 | ### Technical Requirements 23 | This course has the following requirements:
24 | Operating system: macOS / Ubuntu / Debian
25 | Hardware: capable of running Docker 26 | CPU: x86_64 (or amd64), armhf, arm64, s390x (IBM Z), and ppc64le (IBM Power) architectures 27 | RAM: ideally = 8 GB 28 | Mac: hardware must be a 2010 or newer model
29 | 30 | 31 | 32 | ## Related Products 33 | * [Beginning Jenkins](https://prod.packtpub.com/in/application-development/beginning-jenkins) 34 | 35 | * [Mastering Machine Learning AlgorithmsHands-On Continuous Integration and Automation with Jenkins](https://prod.packtpub.com/in/virtualization-and-cloud/hands-continuous-integration-and-automation-jenkins-video) 36 | 37 | * [Practical Jenkins](https://prod.packtpub.com/in/networking-and-servers/practical-jenkins-video) 38 | --------------------------------------------------------------------------------