State of the Union - CI

http://slides.com/rocktavious/uacf-ci/live/

Who am I

Kyle Rockman

  • Infrastructure Team
  • Build & Release Engineer
  • krockman@underarmour.com
  • @rockman on slack

Agenda

  • Local Development (docker-compose)
  • Jenkins Pipeline (workflow)
  • Deployment (parlour)
  • Instrumentation (ELK)
  • The future

Local Development

Docker Containers facilitate local development:

  • Build like Jenkins
  • Test like Jenkins
  • Run like Production

docker-compose.yml

Local Development

base:
  build: .
  dockerfile: parlour.dockerfile

# SERVICES
parlour:
  extends:
    file: docker-compose.yml
    service: base
  ports:
  - "8000:8000"
  environment:
  - "CONSUL_URL=https://consul.uacf.io"
  volumes:
  - $PWD:/uacf

# TESTS
unittest:
  extends:
    file: docker-compose.yml
    service: base
  command: py.test ...
  volumes:
  - $PWD:/uacf

# CI TESTS
ci-unittest:
  image: docker.uacf.io/parlour/parlour:CIVERSION
  command: py.test ...

Jenkins Pipeline

  • Extended groovy syntax
  • Ability to program your pipeline like a giant script
  • A single job folder in jenkins that runs the workflow for every branch in gitlab when changes happen
  • Easy view of which branches are failing the pipeline
  • Test out different pipelines on a branch
  • No need for Infrastructure to get involved when you need to change how your jobs work
  • Will still consult on complex pipelines and best practices where/when needed

Jenkins Pipeline

Jenkins Pipeline

env.GIT_PROJECT = "infra/parlour"

def images = [
    parlour: [
        DOCKER_IMAGE_NAME: "parlour/parlour",
        DOCKER_CONTEXT_PATH: ".",
        DOCKER_FILE: "./parlour.dockerfile",
    ],
]

def tests = [
    pep8: [
        TEST_YAML: "./docker-compose.yml",
        TEST_TARGET: "ci-pep8",
    ],
    unittest: [
        TEST_YAML: "./docker-compose.yml",
        TEST_TARGET: "ci-unittest",
        HAS_JUNIT_REPORT: true,
        HAS_PYTHON_HTML_REPORT: true,
    ]
]

stage 'Init'
lib = node('swarm') {
    git 'git@scm-main-01.dc.myfitnesspal.com:infra/CI.git'
    load 'docker_v2/lib.groovy'
}

lib.start()
if (env.BRANCH_NAME in ["master"]){
    lib.publish(images, true)
} else {
    lib.build(images, true)
    lib.test(tests, true)
}
lib.finish()

Jenkins Pipeline




stage 'Init'
lib = node('swarm') {
    git 'git@scm-main-01.dc.myfitnesspal.com:infra/CI.git'
    load 'docker_v2/lib.groovy'
}




lib.start()
if (env.BRANCH_NAME in ["master"]){
    lib.publish(images, true)
} else {
    lib.build(images, true)
    lib.test(tests, true)
}
lib.finish()

Jenkins Pipeline

env.GIT_PROJECT = "infra/parlour"

def images = [
    parlour: [
        DOCKER_IMAGE_NAME: "parlour/parlour",
        DOCKER_CONTEXT_PATH: ".",
        DOCKER_FILE: "./parlour.dockerfile",
    ],
]

def tests = [
    pep8: [
        TEST_YAML: "./docker-compose.yml",
        TEST_TARGET: "ci-pep8",
    ],
    unittest: [
        TEST_YAML: "./docker-compose.yml",
        TEST_TARGET: "ci-unittest",
        HAS_JUNIT_REPORT: true,
        HAS_PYTHON_HTML_REPORT: true,
    ]
]

Jenkins Pipeline

def images = [
    uacf_amzn: [
        DOCKER_IMAGE_NAME: "uacf_amzn/uacf_base",
        DOCKER_CONTEXT_PATH: ".",
        DOCKER_FILE: "./Dockerfile",
        DOCKER_IMAGE_VERSION: "2015.09_2",
    ],
    java8: [
        DOCKER_IMAGE_NAME: "uacf_amzn/java8",
        DOCKER_CONTEXT_PATH: "./java8/",
        DOCKER_FILE: "./java8/Dockerfile",
        DOCKER_IMAGE_VERSION: "8u66b17_2",
        NEEDS_INTERIM_PARENT: true,
    ],
    java8_gradle: [
        DOCKER_IMAGE_NAME: "uacf_amzn/java8_gradle",
        DOCKER_CONTEXT_PATH: "./java8/gradle/",
        DOCKER_FILE: "./java8/gradle/Dockerfile",
        DOCKER_IMAGE_VERSION: "2.9_2",
        NEEDS_INTERIM_PARENT: true,
    ]
]
lib.start()
if (env.BRANCH_NAME in ["master"]){
    lib.publish(images, true)
} else {
    lib.build(images, false)
}
lib.finish()

Jenkins Pipeline

def images = [
    productcatalog: [
        DOCKER_IMAGE_NAME: "lsr/product-catalog",
        DOCKER_CONTEXT_PATH: ".",
        DOCKER_FILE: "./Dockerfile",
    ],
    paymentsdb: [
        DOCKER_IMAGE_NAME: "lsr/paymentsdb",
        DOCKER_CONTEXT_PATH: "./docker/paymentsdb",
        DOCKER_FILE: "./docker/paymentsdb/Dockerfile",
    ]
]

def tests = [
    unittest: [
        TEST_YAML: "docker-compose.yml",
        TEST_TARGET: "ci-unittest",
        HAS_JUNIT_REPORT: true,
        JUNIT_REPORT_REGEX: "mfp.platform.*.xml"
    ],
]

lib.gitlab_pipeline_v1(images, tests, 'jenkins', 'master')

Jenkins Pipeline

def gitlab_pipeline_v1(images, tests,
                       develop='develop',
                       master='master',
                       has_release=false) {
    echo "Master Branch: $master"
    echo "Develop branch: $develop"
    echo "Checking if we should build $env.BRANCH_NAME ..."
    isDevelop = env.BRANCH_NAME.startsWith(develop)
    isMaster = env.BRANCH_NAME.startsWith(master)
    if (isDevelop || isMaster) {
        start()
        try {
            build(images, true)
            test(tests, true)
            if (isMaster) {
                publish(images, true)
                if (has_release) {
                    release(images, true)
                }
            }
        } catch (e) {
            currentBuild.result = 'UNSTABLE'
            printStackTrace()
        } finally {
            finish()
        }
    }
}

Deployment

  • Provide a service API for programmatic control
  • Provide a web interface for developers
  • Docker containers act as a binary packaging system
  • Docker containers support multi-tenancy in the future
  • Convergence model over explicit orchestration
  • Easy access to change secrets and settings
  • Become an events producer via Kafka in the future

Deployment

Deployment UI

Any UI help is warmly welcomed!

Instrumentation

Instrumentation

The Future

  • Central Git Remote
  • Standardized CD via API call in Jenkins Pipeline script
  • More pipeline libraries for different workflows
  • Default alerts setup in Librato
  • Self Service provisioning of development clusters
  • Metadata about your service
  • Cost tracking / estimation of provisioned resources
  • Infra Events Kafka Messages

Questions

Questions ?

State of the Union - CI

By Kyle Rockman

State of the Union - CI

  • 1,088