GoLang

Criar pipelines de implantação contínua com Golang e Jenkins

Há algumas semanas, escrevi sobre a implantação contínua de um aplicativo escrito com a linguagem de programação Go usando um serviço popular chamado Travis CI. Esse exemplo demonstrou a criação de um aplicativo que usava um Couchbase banco de dados NoSQL, criando testes de unidade, executando esses testes no pipeline de integração contínua do Golang e, por fim, implantando o aplicativo em algum servidor remoto quando tudo for bem-sucedido.

O Travis CI não é o único serviço que oferece esses recursos. Na verdade, você pode hospedar seu próprio serviço de CI/CD usando o Jenkins.

Veremos como usar o Jenkins para um pipeline de um aplicativo Golang, permitindo a integração e a implantação contínuas.

Se você ainda não leu meu tutorial anterior Golang com Travis CIRecomendo que você o faça, pois ele fornece muitas explicações úteis. Muito do mesmo material aparecerá aqui, mas será explicado de forma diferente, portanto, duas explicações podem ser úteis.

Se quiser experimentar de verdade este tutorial Jenkins with Golang, você precisará de Servidor Couchbase instalado em algum lugar. O objetivo é fazer com que o aplicativo seja executado e use essa instância do banco de dados após a implantação.

Desenvolvimento de um aplicativo Go com Couchbase

Para ter sucesso com este tutorial, precisaremos de um aplicativo Go para testar e implantar. Se você quiser se adiantar, fiz o upload de um projeto funcional no GitHub. Na verdade, é o mesmo projeto do exemplo do Travis CI.

Se você preferir conhecer o projeto, vamos dedicar algum tempo para isso.

Em algum lugar em seu $GOPATH criar um arquivo chamado main.go e inclua o seguinte código Go. Vamos detalhá-lo depois.

O aplicativo não faz muita coisa, mas há muita coisa acontecendo.

Nas importações, você notará que usamos o SDK do Couchbase para Go. Para poder compilar esse projeto, você precisará fazer o download do SDK. Isso pode ser feito com o seguinte comando:

Antes de começarmos a analisar o código, precisamos dar um passo atrás e descobrir como esse aplicativo deve funcionar.

O objetivo aqui é conectar-se ao banco de dados NoSQL, Couchbase, recuperar alguns dados e criar alguns dados. Naturalmente, isso seria muito fácil por meio do SDK, mas queremos criar testes de unidade para o nosso aplicativo. É uma prática recomendada nunca testar um banco de dados em um teste de unidade. Guarde isso para seus testes de integração. Se não estivermos testando o banco de dados, precisaremos criar cenários de simulação.

Em vez de criar um monte de maluquices, a melhor maneira de dividir entre cenários reais e simulados é criar uma interface para ambos com Go. O aplicativo principal usará as classes reais como parte da interface, enquanto os testes usarão a simulação.

Por esse motivo, precisamos criar uma interface para o Couchbase Go SDK Balde componente.

Um Couchbase Bucket tem muito mais funções do que Obter e Inserirmas essas serão as únicas funções que usaremos neste exemplo. Para simplificar, mais adiante no aplicativo, criaremos uma função estrutura com a nova interface.

Haverá apenas um modelo de dados para este exemplo. Usaremos um modelo de dados baseado no modelo Pessoa estrutura de dados. Ela pode ser alterada livremente sem afetar nosso aplicativo.

Dê uma olhada em uma de nossas funções para a qual eventualmente teremos testes unitários:

No GetPersonDocument estamos usando uma função BucketInterface e obter um documento específico pela chave do documento.

Da mesma forma, se quisermos criar dados, teremos o seguinte:

Sinto que preciso reiterar isso, mas essas funções foram projetadas para serem mais complexas do que o necessário. Estamos fazendo isso porque queremos demonstrar alguns testes. Se você se sentir melhor, adicione um pouco mais de complexidade a elas em vez de apenas Obter e Inserir funcionalidade.

Por fim, temos o seguinte, que é executado em tempo de execução:

Quando o aplicativo é executado, estabelecemos uma conexão com o Couchbase usando variáveis de ambiente. O Bucket aberto é definido como nosso BucketInterfacee, em seguida, as duas funções são executadas.

Então, como podemos testar isso?

Crie um arquivo em seu projeto chamado main_test.go com o seguinte código:

Você perceberá que esse arquivo é bastante longo e que também estamos incluindo outro pacote personalizado. Antes de analisarmos o código, vamos fazer o download desse pacote. Na linha de comando, execute o seguinte:

O pacote mapstructure nos permitirá pegar mapas e convertê-los em estruturas de dados reais, como o Pessoa estrutura de dados que havíamos criado anteriormente. Basicamente, isso nos dá um pouco de flexibilidade no que podemos fazer.

Se você quiser saber mais sobre o pacote mapstructure, confira um artigo anterior que escrevi intitulado, Decodificar valores de mapas em estruturas nativas da Golang.

Com as dependências instaladas, agora podemos dar uma olhada no código. Lembra-se de como usamos o Bucket do Go SDK em nosso código principal? No código de teste, não faremos isso.

Em nosso código de teste, estamos criando um arquivo estruturamas estamos definindo-o como BucketInterface no Banco de dados que foi criada em nosso código principal.

A configuração real da estrutura de dados ocorre no TestMain que é executada antes de todos os outros testes:

Agora, como estamos usando um MockBucketEle não tem todas as funções que o gocb.Bucket poderia ter tido. Em vez disso, precisamos confiar na BucketInterface definição.

Precisamos criar um Obter e um Inserir conforme definido na interface.

Começando com o Obter temos o seguinte:

Se estivermos usando um MockBucket e tentamos ObterEsperamos que apenas uma chave seja válida. Lembre-se de que este é um teste, portanto, somos nós que estabelecemos as regras. Se garoto é usado como uma chave, retornamos alguns dados simulados; caso contrário, retornamos um chave não encontrada erro. Como estamos trabalhando com vários tipos de dados em potencial, precisamos converter nossos dados usando a função converter função. Essencialmente, estamos transformando uma interface em JSON e, em seguida, transformando-a de volta.

Agora vamos dar uma olhada nessa simulação Inserir função.

Se tentarmos inserir dados usando nosso Bucket de simulação, esperamos que a chave não seja igual a garotocaso contrário, gera um erro.

Com as funções de interface criadas, podemos nos concentrar nos testes reais que testam as funções no código principal em Go.

O TestGetPersonDocument usará nosso Bucket de simulação no GetPersonDocument function. Lembre-se de que estamos usando interfaces, portanto, o Go descobrirá qual função de interface usar, seja a função real do Couchbase Go SDK ou a função de simulação que usamos. Dependendo dos resultados, é isso que acontece no teste.

O TestCreatePersonDocument não é diferente do anterior. Estamos chamando o CreatePersonDocumentmas estamos usando nosso Bucket de simulação com a função de simulação Inserir função.

Neste momento, temos um aplicativo Go funcional com testes e estamos prontos para a integração contínua e a implantação contínua.

Instalação e configuração do Jenkins para implementações de SSH e Golang

A próxima etapa pressupõe que você tenha um servidor remoto pronto para receber implementações. Como eu não tinha, criei um contêiner do Docker com o Ubuntu. Na verdade, tanto a minha instalação do Jenkins quanto o servidor remoto estão usando o Docker.

Se você quiser seguir o que eu fiz, dê uma olhada nisto. Na linha de comando, execute o seguinte para iniciar um contêiner do Ubuntu:

O comando acima implantará um contêiner do Ubuntu e o nomeará ubuntu. Depois de implantado, você estará conectado por meio do terminal interativo. Não abri nenhuma porta porque a comunicação entre contêineres não precisará de uma porta mapeada.

O contêiner do Ubuntu não terá um servidor SSH disponível, portanto, precisamos instalá-lo. No shell do Ubuntu, execute o seguinte:

Os comandos acima instalarão servidor openssh e iniciá-lo. Enquanto isso, provavelmente deveríamos criar uma combinação de chave pública e privada para o Jenkins usar.

No shell do Ubuntu, execute o seguinte:

Quando terminar, copie o ~/.ssh/id_rsa.pub conteúdo em ~/.ssh/authorized_keys pois usaremos a chave privada no servidor Jenkins.

Lembre-se de que também estou usando o Jenkins como um contêiner do Docker. Você não precisa usar nenhum contêiner se não quiser. Tudo deve se traduzir bem.

Se estiver usando o Docker, crie um contêiner do Jenkins executando o seguinte:

O comando acima implantará o Jenkins no modo desanexado e mapeará algumas portas para nós.

Quando você visita http://localhost:8080 em seu navegador da Web, siga as etapas do assistente e certifique-se de optar por instalar os plug-ins recomendados.

Quando você chegar ao painel principal do Jenkins, selecione Gerenciar Jenkins -> Gerenciar plug-ins pois precisamos fazer o download de algumas coisas.

Golang Jenkins Plugins

Precisaremos de uma maneira de compilar nosso código Go, portanto, precisaremos do Ir plugin. Vamos precisar executar nossos próprios scripts personalizados para a construção, portanto, precisamos do PostBuildScript plugin. Por fim, queremos poder publicar em um servidor remoto e executar comandos, portanto, precisaremos do plug-in Publicar por SSH que vem com outros plug-ins incluídos.

Depois que o download dos plug-ins for concluído, precisaremos configurá-los globalmente.

No painel principal do Jenkins, selecione Gerenciar Jenkins -> Configuração global de ferramentas e procure a seção Go.

Golang Jenkins Configuration

Você deverá definir quais versões do Go estão disponíveis. Para este projeto, precisamos apenas da versão 1.8, mas o restante fica a seu critério.

A próxima etapa é configurar nossas chaves SSH para implantação. Lembre-se de que ainda não estamos criando nosso fluxo de trabalho, apenas configurando o Jenkins como um todo.

No painel principal do Jenkins, selecione Gerenciar Jenkins -> Configurar sistema e localize a seção SSH.

Você vai querer fornecer sua chave privada e as informações de conexão do servidor. Se tanto o Jenkins quanto o servidor remoto forem contêineres do Docker na mesma rede que a minha, não se esqueça de usar os endereços IP ou nomes de host do contêiner, e não o host local.

Com tudo configurado, selecione Novo item no painel principal do Jenkins.

New Jenkins Golang Project

Você vai querer dar um nome a ele e selecionar Projeto Freestyle para que possamos adicionar nosso próprio fluxo de trabalho. Observe o nome, pois ele será o binário do projeto que será criado.

Agora podemos definir nosso fluxo de trabalho.

Começaremos com o Gerenciamento de código-fonte seção. Lembre-se, tenho esse projeto em GitHubportanto, você definitivamente deve tirar proveito disso.

Jenkins Source Code Management Golang

Como o Jenkins, neste exemplo, está sendo executado no localhost e não em um domínio, não podemos realmente fazer nada com os acionadores de compilação. Para este exemplo, vamos acionar as coisas manualmente.

Antes de tentarmos executar qualquer script, precisamos definir o ambiente de compilação para a versão do Go especificada anteriormente.

Jenkins Golang Build Environment

Quando o fluxo de trabalho for iniciado, ele baixará e instalará essa versão do Go antes de executar testes ou compilações.

Para a fase de construção, vamos realizar três etapas diferentes, separadas para manter o fluxo das coisas bem limpo.

Jenkins Golang Build

A primeira etapa de compilação é fazer o download dos pacotes Go. Depois que tivermos nossos pacotes, poderemos executar nossos testes. Depois de executar os testes, podemos fazer um ir construir para criar nosso binário. Se alguma dessas etapas falhar, toda a compilação falhará, e é assim que deve ser.

A etapa final é a implantação. Na seção Ações pós-construção, queremos enviar nosso binário por SSH e executá-lo.

Jenkins Deploy with SSH

Na verdade, haverá dois conjuntos de transferências envolvidos nesse processo.

A primeira fase é pegar nosso arquivo de origem, que é o binário, e enviá-lo usando o perfil SSH que criamos anteriormente. Depois que o arquivo for transferido, alteraremos as permissões para que ele possa ser executado.

Depois que o arquivo for carregado, queremos executá-lo de fato usando outro Conjunto de transferência. Em vez de ter um arquivo de código-fonte no segundo conjunto, teremos apenas um comando:

Observe que estou passando variáveis para serem usadas como variáveis de ambiente no aplicativo. Troque-as pelo que você estiver usando ou pense em outra abordagem, como definir essas variáveis no servidor para fins de segurança.

Em teoria, você estaria implantando um aplicativo da Web e esse comando final é usado para iniciar o servidor com informações de conexão.

Conclusão

Você acabou de ver como configurar Jenkins e Golang em um pipeline para implantação contínua. Para completar, usamos de fato o Couchbase e Docker neste exemplo para lidar com o nosso servidor remoto, bem como com o nosso servidor Jenkins. Sua configuração pode ser diferente, mas as etapas são mais ou menos as mesmas.

Se você quiser saber mais sobre como usar o Jenkins e o Go com o Couchbase, confira o artigo Portal do desenvolvedor do Couchbase.

Compartilhe este artigo
Receba atualizações do blog do Couchbase em sua caixa de entrada
Esse campo é obrigatório.

Autor

Postado por Nic Raboy, defensor dos desenvolvedores, Couchbase

Nic Raboy é um defensor das modernas tecnologias de desenvolvimento móvel e da Web. Ele tem experiência em Java, JavaScript, Golang e uma variedade de estruturas, como Angular, NativeScript e Apache Cordova. Nic escreve sobre suas experiências de desenvolvimento relacionadas a tornar o desenvolvimento móvel e da Web mais fácil de entender.

Deixe um comentário

Pronto para começar a usar o Couchbase Capella?

Iniciar a construção

Confira nosso portal do desenvolvedor para explorar o NoSQL, procurar recursos e começar a usar os tutoriais.

Use o Capella gratuitamente

Comece a trabalhar com o Couchbase em apenas alguns cliques. O Capella DBaaS é a maneira mais fácil e rápida de começar.

Entre em contato

Deseja saber mais sobre as ofertas do Couchbase? Deixe-nos ajudar.