Skip to content

Commit

Permalink
add job and use alpine
Browse files Browse the repository at this point in the history
  • Loading branch information
Doug Davis committed Sep 28, 2020
1 parent 0ff7e9d commit c1f4040
Show file tree
Hide file tree
Showing 17 changed files with 193 additions and 78 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ $ ic ce project create --name demos --target
Similar to [hello](hello) except this is written in golang and adds a few
bells-n-whistles to allow you to control what it does when invoked.
- [job](job)<br>
This will create a batch job that will print basic debugging information to
the logs, and then show those logs. It'll create the job with and without
a job definition to show both options.
- [job2app](job2app)<br>
This will demostrate how to create a simple Batch Job and how to have it
communicate with an Application running within the same project.
- [s2i-buildpacks](s2i-buildpacks)<br>
Expand Down
6 changes: 5 additions & 1 deletion helloworld/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
FROM golang
FROM golang:alpine
COPY helloworld.go /
RUN go build -o /helloworld /helloworld.go

# Copy the exe into a smaller base image
FROM alpine
COPY --from=0 /helloworld /helloworld
CMD /helloworld
4 changes: 2 additions & 2 deletions helloworld/helloworld.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func Debug(doit bool, format string, args ...interface{}) {

func main() {
// If env var CRASH is set then crash immediately.
// If it's value is of the form HH:MM then crash at the specified time
// If its value is of the form HH:MM then crash at the specified time
// time. The time is based on time returned from: http://time.nist.gov:13
if date := os.Getenv("CRASH"); date != "" { // Just crash!
// get time: curl http://time.nist.gov:13
Expand Down Expand Up @@ -102,7 +102,7 @@ func main() {
os.Exit(1)
}

// If 'fail' query parameter is there then return it's value
// If 'fail' query parameter is there then return its value
// as the HTTP return code, defaults to '500'
if t, ok := r.URL.Query()["fail"]; ok {
status := 500
Expand Down
6 changes: 5 additions & 1 deletion job/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
FROM golang
FROM golang:alpine
COPY job.go /
RUN go build -o /job /job.go

# Copy exe into a smaller image
FROM alpine
COPY --from=0 /job /job
CMD /job
4 changes: 0 additions & 4 deletions job/Dockerfile.app

This file was deleted.

19 changes: 9 additions & 10 deletions job/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Job2App
# Job

This sample serves two purposes:
- show how to create a simple Batch Job ([`job.go`](./job.go))
- how to have that Job call an Application running in the same project. This
will use the private network within the project - meaning the private
endpoint of the app, not a public-facing one.
This sample shows up to run a batch job. It will create the batch job two ways:
1 - first, it'll create a Job definition (the config informatin about a job)
and then it submits that Job to actually do the work.
2 - second, it'll submit the Job directly without creating the definition
first. Both will generate the same results though.

When the Job is run, each instance will call the App 10 times. Which means
by setting the `array-indices` to a range of 50, the App should be hit 500
times. At the end of `run` it will ask the App for the number of times it
was called, to verify the count.
Each instance of each Job submitted will print, to its logs, its "index",
which is defined by its `JOB_INDEX` environment variable. The `run` script
will print some of the log files to show this.
10 changes: 3 additions & 7 deletions job/build
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
set -ex
export REPOSITORY=${REPOSITORY:-ibmcom}

# First build the app's image and push it
docker build -t ${REPOSITORY}/j2a-app -f Dockerfile.app .
docker push ${REPOSITORY}/j2a-app

# Now build the job's
docker build -t ${REPOSITORY}/j2a-job -f Dockerfile .
docker push ${REPOSITORY}/j2a-job
# Build the job image and push it
docker build -t ${REPOSITORY}/firstjob -f Dockerfile .
docker push ${REPOSITORY}/firstjob
37 changes: 1 addition & 36 deletions job/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,9 @@ package main

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"sync"
)

func main() {
// Get the namespace we're in so we know how to talk to the App
file := "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
namespace, err := ioutil.ReadFile(file)
if err != nil || len(namespace) == 0 {
fmt.Fprintf(os.Stderr, "Missing namespace: %s\n%s\n", err, namespace)
os.Exit(1)
}

count := 10
fmt.Printf("Sending %d requests...\n", count)
wg := sync.WaitGroup{}

// URL to the App
url := "http://app." + string(namespace) + ".svc.cluster.local"

// Do all requests to the App in parallel - why not?
for i := 0; i < count; i++ {
wg.Add(1)
go func() {
defer wg.Done()
res, err := http.Post(url, "", nil)

// Something went wrong
if err != nil || res.StatusCode > 299 {
fmt.Fprintf(os.Stderr, "%d: %s\n%#v\n", i, err, res)
}
}()
}

// Wait for all threads to finish before we exit
wg.Wait()

fmt.Printf("Done\n")
fmt.Printf("Hi from a batch job! My index is: %s\n", os.Getenv("JOB_INDEX"))
}
44 changes: 28 additions & 16 deletions job/run
Original file line number Diff line number Diff line change
@@ -1,43 +1,55 @@
#!/bin/bash

# Env Vars:
# COUNT: number of instances of the job to run
# NUM: number of instances of the job to run
# REPOSITORY: name of the image registry/namespace to get the images

# Clean up previous run
function clean() {
set +x
echo Cleaning...
ic ce jobrun delete -n job -f > /dev/null 2>&1 || true
ic ce app delete -n app -f --wto=0 > /dev/null 2>&1 || true
ic ce job delete -n myjob -f > /dev/null 2>&1 || true
ic ce jobrun delete -n doit -f > /dev/null 2>&1 || true
ic ce jobrun delete -n doit2 -f > /dev/null 2>&1 || true
rm -f out
}

clean
[[ "$1" == "clean" ]] && exit 0

set -ex
export REPOSITORY=${REPOSITORY:-ibmcom}
export COUNT=${COUNT:-50}
export NUM=${COUNT:-10}

# Create the app
ic ce app create -n app --min=1 --max=1 --image ${REPOSITORY}/j2a-app
# Create a Job definition
ic ce job create --name myjob --array-indices=1-${NUM} \
--image ${REPOSITORY}/firstjob

# Get metadata about the app for later use
URL=$(ic ce app get -n app -o jsonpath={.status.url})
# Now submit the job using that definition
ic ce jobrun submit --name doit --job myjob

# Create/run the job, passing in the project/namespace
ic ce jobrun submit -n job --ai=1-${COUNT} --image ${REPOSITORY}/j2a-job
# Wait for it to finish...
until ic ce jobrun get --name doit -o jsonpath={.status.succeeded} | grep $NUM
do
sleep 3
done

# Now submit a job w/o creating a job definition first
ic ce jobrun submit --name doit2 --array-indices=1-${NUM} \
--image ${REPOSITORY}/firstjob

# Wait for it to finish...
until ic ce jobrun get -n job -o jsonpath={.status.succeeded} | grep $COUNT; do
until ic ce jobrun get --name doit2 -o jsonpath={.status.succeeded} | grep $NUM
do
sleep 3
done

# Check the app to see how many times the app was hit
if ! [[ "Count: $((COUNT*10))" == "$(curl -s $URL)" ]]; then
echo "Should be $((COUNT*10))"
exit 1
fi
# Show the stats about the job
ic ce jobrun get --name doit2

# Now look at a view of the logs to make sure it worked
ic ce jobrun logs --instance doit2-1-0
ic ce jobrun logs --instance doit2-2-0 | grep "Hi from"

# Clean up
clean
8 changes: 8 additions & 0 deletions job2app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM golang:alpine
COPY job.go /
RUN go build -o /job /job.go

# Copy the exe into a smaller base image
FROM alpine
COPY --from=0 /job /job
CMD /job
8 changes: 8 additions & 0 deletions job2app/Dockerfile.app
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM golang:alpine
COPY app.go /
RUN go build -o /app /app.go

# Copy the exe into a smaller base image
FROM alpine
COPY --from=0 /app /app
CMD /app
12 changes: 12 additions & 0 deletions job2app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Job2App

This sample serves two purposes:
- show how to create a simple Batch Job ([`job.go`](./job.go))
- how to have that Job call an Application running in the same project. This
will use the private network within the project - meaning the private
endpoint of the app, not a public-facing one.

When the Job is run, each instance will call the App 10 times. Which means
by setting the `array-indices` to a range of 50, the App should be hit 500
times. At the end of `run` it will ask the App for the number of times it
was called, to verify the count.
File renamed without changes.
15 changes: 15 additions & 0 deletions job2app/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# Env Vars:
# REPOSITORY: name of the image registry/namespace to store the images

set -ex
export REPOSITORY=${REPOSITORY:-ibmcom}

# First build the app's image and push it
docker build -t ${REPOSITORY}/j2a-app -f Dockerfile.app .
docker push ${REPOSITORY}/j2a-app

# Now build the job's
docker build -t ${REPOSITORY}/j2a-job -f Dockerfile .
docker push ${REPOSITORY}/j2a-job
45 changes: 45 additions & 0 deletions job2app/job.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

import (
"fmt"
"io/ioutil"
"net/http"
"os"
"sync"
)

func main() {
// Get the namespace we're in so we know how to talk to the App
file := "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
namespace, err := ioutil.ReadFile(file)
if err != nil || len(namespace) == 0 {
fmt.Fprintf(os.Stderr, "Missing namespace: %s\n%s\n", err, namespace)
os.Exit(1)
}

count := 10
fmt.Printf("Sending %d requests...\n", count)
wg := sync.WaitGroup{}

// URL to the App
url := "http://app." + string(namespace) + ".svc.cluster.local"

// Do all requests to the App in parallel - why not?
for i := 0; i < count; i++ {
wg.Add(1)
go func() {
defer wg.Done()
res, err := http.Post(url, "", nil)

// Something went wrong
if err != nil || res.StatusCode > 299 {
fmt.Fprintf(os.Stderr, "%d: %s\n%#v\n", i, err, res)
}
}()
}

// Wait for all threads to finish before we exit
wg.Wait()

fmt.Printf("Done\n")
}
43 changes: 43 additions & 0 deletions job2app/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

# Env Vars:
# COUNT: number of instances of the job to run
# REPOSITORY: name of the image registry/namespace to get the images

# Clean up previous run
function clean() {
set +x
echo Cleaning...
ic ce jobrun delete -n job -f > /dev/null 2>&1 || true
ic ce app delete -n app -f --wto=0 > /dev/null 2>&1 || true
}

clean
[[ "$1" == "clean" ]] && exit 0

set -ex
export REPOSITORY=${REPOSITORY:-ibmcom}
export COUNT=${COUNT:-50}

# Create the app
ic ce app create -n app --min=1 --max=1 --image ${REPOSITORY}/j2a-app

# Get metadata about the app for later use
URL=$(ic ce app get -n app -o jsonpath={.status.url})

# Create/run the job, passing in the project/namespace
ic ce jobrun submit -n job --ai=1-${COUNT} --image ${REPOSITORY}/j2a-job

# Wait for it to finish...
until ic ce jobrun get -n job -o jsonpath={.status.succeeded} | grep $COUNT; do
sleep 3
done

# Check the app to see how many times it was hit
if ! [[ "Count: $((COUNT*10))" == "$(curl -s $URL)" ]]; then
echo "Should be $((COUNT*10))"
exit 1
fi

# Clean up
clean
6 changes: 5 additions & 1 deletion s2i-dockerfile/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
FROM golang
FROM golang:alpine
COPY app.go /
RUN go build -o /app /app.go

# Copy the exe into a smaller base image
FROM alpine
COPY --from=0 /app /app
CMD /app

0 comments on commit c1f4040

Please sign in to comment.