Integracion continue con Travis CI y Docker


travis

Introducción

En este artículo veremos cómo crear un proceso simple de integración continua utilizando Github, Travis-CI y Docker HUB. Los archivos utilizados aquí se pueden encontrar AQUÍ. En el próximo artículo continuaremos con lo que tenemos aquí para proporcionar despliegue continuo, posiblemente usando Jenkins o quizás Travis. Hazme saber cuál prefieres ver.


Primero lo primero
Aplicación

Revisaremos el archivo docker, el código de la aplicación y el archivo travis-ci, así que comencemos con la aplicación main.go:

package main

import (
    "fmt"
    "log"
    "net"
    "net/http"
    "os"
    "strconv"
)

func httphandler(w http.ResponseWriter, r *http.Request) {
    ipAddress, _, _ := net.SplitHostPort(r.RemoteAddr)
    fmt.Fprintf(w, "%s", ipAddress)
}

func main() {
    port, err := strconv.Atoi(os.Getenv("WHATISMYIP_PORT"))
    if err != nil {
        log.Fatalf("Please make sure the environment variable WHATISMYIP_PORT is defined and is a valid integer [1024-65535], error: %s", err)
    }

    listener := fmt.Sprintf(":%d", port)

    http.HandleFunc("/", httphandler)
    log.Fatal(http.ListenAndServe(listener, nil))
}

Revisemos rápidamente lo que hace este código. Primero verificamos el puerto a utilizar, luego lo convertimos en un número, registramos el manejador para nuestra función HTTP y escuchamos las solicitudes. Este código imprimirá nuestra dirección IP como se esperaría por el nombre.


Luego el código de main_test.go:

package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHandler(t *testing.T) {
    req, err := http.NewRequest("GET", "/", nil)
    if err != nil {
        t.Fatal(err)
    }

    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(httphandler)

    handler.ServeHTTP(rr, req)

    if status := rr.Code; status != http.StatusOK {
        t.Errorf("Status code got: %v want %v",
            status, http.StatusOK)
    }

    expected := ``
    if rr.Body.String() != expected {
        t.Errorf("Unexpected body got: %v want %v",
            rr.Body.String(), expected)
    }
}

La prueba es bastante simple, solo verifica que el servidor web funcione al intentar acceder a / y comprobando que el cuerpo esté vacío y el código de estado sea 200.


Docker

A continuación, el Dockerfile:

FROM golang:1.12-alpine

LABEL maintainer="[email protected]"

# Set the Current Working Directory inside the container
WORKDIR $GOPATH/src/github.com/kainlite/whatismyip-go
COPY . .

# Download all the dependencies
# https://stackoverflow.com/questions/28031603/what-do-three-dots-mean-in-go-command-line-invocations
RUN go get -d -v ./...

# Install the package and create test binary
RUN go install -v ./... && \
    CGO_ENABLED=0 GOOS=linux go test -c

# This container exposes port 8080 to the outside world
EXPOSE 8000

# Set default environment variable values
ENV WHATISMYIP_PORT 8000

# Perform any further action as an unprivileged user.
USER nobody:nobody

# Run the executable
CMD ["whatismyip-go"]

Configuramos el directorio de trabajo para satisfacer a go, luego obtenemos las dependencias e instalamos nuestro binario. También generamos un binario de prueba, exponemos el puerto que queremos utilizar y configuramos el usuario como nobody en caso de que alguien pueda explotar nuestra aplicación y acceder al contenedor. Finalmente, establecemos el comando a ejecutar en docker run.

Travis

Y por último, pero no menos importante, el archivo .travis.yml:

language: go

services:
  - docker

before_install:
- docker build --no-cache -t ${TRAVIS_REPO_SLUG}:${TRAVIS_COMMIT} .
- docker run ${TRAVIS_REPO_SLUG}:${TRAVIS_COMMIT} /go/src/github.com/kainlite/whatismyip-go/whatismyip-go.test
- docker run -d -p 127.0.0.1:8000:8000 ${TRAVIS_REPO_SLUG}:${TRAVIS_COMMIT}

script:
  - curl 127.0.0.1:8000
  - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
  - docker push ${TRAVIS_REPO_SLUG}:${TRAVIS_COMMIT}

Le indicamos a Travis que ejecutaremos código Go y Docker. Luego, construimos la imagen, ejecutamos las pruebas y después la aplicación como parte de la inicialización. Después de eso, validamos que la aplicación funcione y, por último, iniciamos sesión en Docker Hub y subimos la imagen. Las cosas importantes a tener en cuenta aquí son que usamos variables, por ejemplo, el nombre del repositorio, el SHA del commit, y el nombre de usuario y contraseña de Docker de manera segura, ya que Travis-CI oculta los valores que le indicamos.


Juntando todo

Hasta ahora, tenemos el repositorio funcionando, la configuración de Travis, el Dockerfile y la aplicación, pero ahora necesitamos usarlo. Necesitarás crear una cuenta de Travis para que esto funcione, luego vincula tu cuenta de GitHub con Travis. Podrás sincronizar tus repositorios y deberías ver algo como esto: image Una vez que tu cuenta esté vinculada, podrás sincronizar y habilitar los repositorios para que se construyan.


Después de habilitar el repositorio, puedes configurar algunos detalles como variables de entorno. Aquí estableceremos las credenciales para Docker Hub. image


Y ahora crearemos el repositorio en Docker Hub: image Después de que se crea el repositorio, podemos activar una compilación desde Travis o enviar un commit al repositorio para activar una compilación y validar que todo funciona.


Deberías ver algo como esto en Travis si todo salió bien: image Puedes validar que todo salió bien revisando el SHA del commit que activó la compilación.


Y en Docker Hub: image El mismo SHA se utilizará para etiquetar la imagen.


Notas finales

Publicaré algunos artículos sobre CI y CD, y buenas prácticas que los DevOps/SRE deberían tener en cuenta: consejos, trucos y ejemplos completos de despliegue. Esta es la primera parte de una posible serie de dos o tres artículos con un ejemplo básico pero completo de CI primero y luego CD. Esto, por supuesto, puede cambiar, y cualquier comentario será muy apreciado :).

Algunos enlaces útiles para Travis y Docker y la lista de variables de entorno que se pueden usar.


Errata

Si encuentras algún error o tienes alguna sugerencia, por favor envíame un mensaje para que se corrija.



No tienes cuenta? Regístrate aqui

Ya registrado? Iniciar sesión a tu cuenta ahora.

Iniciar session con GitHub
Iniciar sesion con Google
  • Comentarios

    Online: 0

Por favor inicie sesión para poder escribir comentarios.

by Gabriel Garrido