Integracion continue con Travis CI y Docker
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: 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.
Y ahora crearemos el repositorio en Docker Hub: 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: Puedes validar que todo salió bien revisando el SHA del commit que activó la compilación.
Y en Docker Hub: 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.
-
Comentarios
Online: 0
Por favor inicie sesión para poder escribir comentarios.