Variáveis de ambiente usadas no Golang 1.14

Rogerio Angeliski
Ship It!
Published in
6 min readJul 30, 2020

--

Uma coisa bem comum quando começamos a lidar com uma nova linguagem é não se preocupar com todos os detalhes que ficam “por baixo do capô”. Eu comecei a aprender Golang em Dezembro e comecei pelo mais simples: sintaxe.

Para o meu caso, esse foi um caminho válido, pois me ajudou a praticar a linguagem sem me preocupar com muitos detalhes. Mas chega um momento em que se você realmente quer aprender algo, você precisa abrir o capô e olhar lá dentro.

Vou contar como eu fiquei conhecendo as variáveis de ambiente que o Golang usa internamente.

Só mais um dia normal no trabalho, ou seja: Problemas

Nossa dia a dia é resolver problemas e entregar valor para o cliente, às vezes, através de código. Se você discorda, ou não entendeu a afirmação, pode olhar essa talk do Paulo Silveira que elucida bem meu ponto.

Acontece que, nos últimos meses, a RD vem investindo bastante na linguagem Golang, nem sempre fazendo uso de monorepos. Isso acabou tornando difícil para nosso time fazer uso de dependência privadas (já que isso não é tão simples de fazer).

Para resolver essa questão, tivemos que ir atrás de soluções (que vai ficar para outro post) e entender como alterar o valor de variáveis de ambientes específicas pode mudar o comportamento ao buscar dependências. Só depois de entender essas variáveis que a solução fica clara.

As variáveis

Vamos dar uma olhada em algumas variáveis, presentes na versão 1.14, se você quiser saber quais são os valores em uso pelo seu ambiente, você pode rodar no terminal: `go env`

GO111MODULE

Essa variável foi introduzida a partir da versão 1.11, junto com o Go Modules, permitindo que você possa fazer uso do go modules e por consequência tenha um controle mais estável das suas dependências, além de remover a necessidade de ter todos os seus projetos no diretório GOPATH/src.

Você pode ler muito mais detalhes nesse post: Why is GO111MODULE everywhere, and everything about Go Modules

GOPROXY

Essa variável permite definir um Go module proxy, que basicamente vai ser uma aplicação que vai intermediar sua requisição de dependências.

O valor padrão é https://proxy.golang.org mas você pode fazer uso de outros, como o JFrog por exemplo.

Parênteses: Tem algum benefício em usar um Go Proxy?

Aqui eu queria parar alguns momentos para falar sobre os benefícios de usar um proxy para resolver as dependências do seu projeto.

Ao utilizar o Go Modules nas versões 1.11 e 1.12 (que estavam em sua versão preliminar) alguns problemas poderiam surgir:

  • Velocidade de resolução de dependências muito baixa e custosa — Adicionar uma dependência no go.mod era custoso, já que toda árvore precisava ser acessada e resolvida para isso. O que gerava um custo desnecessário só para resolver as suas dependências.
Demonstração de gasto desnecessário ao buscar dependências
Fonte: Katie Hockman — Go Module Proxy: Life of a Query
  • Dependências podiam sumir do dia para noite — Outra coisa que a falta de um package manager (igual o que o NPM faz) traz é que qualquer um pode deletar seu projeto da versão de controle (ou tornar ele privado). Isso deixa você refém do autor, já que seu projeto depende que ele nunca delete a dependência. (O NPM sabe bem disso agora)

Na versão 1.13 foi introduzido o Mirror Proxy para resolver esses dois problemas. O Proxy por si só permite que a resolução de dependências seja feita de modo mais efetivo, fazendo uso dos metadados da dependência para resolver a árvore de dependências. Isso só é possível devido a implementação do Proxy, que permite responder para o CLI informações de maneira mais efetiva. Vamos dar uma olhada no processo todo:

Imagem demonstrando o processo para resolver dependências do Go Module Fonte: Katie Hockman — Go Module Proxy: Life of a Query

O primeiro passo desse processo é solicitar para o Proxy (através do endpoint GET $GOPROXY/<module>/@v/list) quais são as versões conhecidas desse módulo.

Nesse caso, utilizaremos a última versão retornada, já que não foi informada nenhuma versão em específico, solicitando em seguida os metadados dela (através do endpoint GET $GOPROXY/<module>/@v/<version>.info). Isso é necessário para os casos onde fazemos referência a um commit ou branch, já que a versão retornada será diferente do especificado.

O próximo passo é solicitar o arquivo .mod para que possa ser realizada a checagem da árvore de dependências (através do endpoint GET GOPROXY/<module>/@v/<version>.mod).

Uma vez que o arquivo é retornado, é necessário percorrer esse processo (obter o .info e .mod) para todas dependências, garantindo assim a consistência.

A grande vantagem do Proxy é que nessa etapa era necessário recuperar todo o arquivo de dependências para resolver essa informação (ou seja, a dependência era recuperada como um todo, sendo que só era necessário o metadado da mesma), agora o arquivo recuperado é muito menor, fazendo um uso mais efetivo da informação.

A etapa final é apenas recuperar a dependência necessária (através do endpoint GET $GOPROXY/<module>/@v/<version>.zip).

Isso resolve o problema de latência na resolução das dependências do projeto, mas para resolver o problema de ter dependências desaparecendo é necessário usar um tipo especial de Proxy, o Mirror. O Mirror funciona exatamente como um proxy, mas ele adiciona uma funcionalidade extra que é fazer o cache das dependências, permitindo assim que mesmo que essas dependências sejam removidas da fonte original (O Github por exemplo), elas continuam existindo e podem ser resolvidas através dele.

Se você está usando a versão 1.13 ou mais novas, não precisa se preocupar com isso, já que o default é usar o https://proxy.golang.org que é um Mirror Proxy que entrega isso tudo por padrão para o seu desenvolvimento.

GOSUMDB

Quando você faz o download de uma dependência, como você sabe que ela é verdadeira? Como garantir que ninguém modificou ela inserindo algum bug (ou código malicioso) nela?

Uma prática comum de mercado é fazer uso do checksum para isso, onde basicamente nós fazemos uma verificação em uma fonte confiável se a integridade da nossa dependência é válida. O Golang faz isso por padrão, onde o valor dessa env por padrão é sum.golang.org, um database gratuito oferecido pelo google.

GONOPROXY

Essa variável serve para você dizer que as dependências devem ser buscadas diretamente do controle de versão (Github em muitos casos, mas pode ser qualquer um) sem passar pelo Proxy. Suas dependências privadas por exemplo, não vão estar no repositório público, então elas vão ser recuperadas diretamente do controle de versão.

GONOSUMDB

Essa variável serve para você dizer que as suas dependências não devem ser verificadas pelo checksum. Muito cuidado ao usar isso, pois aqui pode haver uma brecha de segurança. Você pode fazer uso das suas dependências privadas aqui, mas confiar em terceiros pode facilmente se tornar um problema crítico de segurança.

GOPRIVATE

Se você estava prestando atenção, percebeu que para fazer uso de dependências privadas precisaria definir a variável GONOPROXY e GONOSUMDB, evitando assim o uso do proxy e do checksum. Isso não é necessário, definindo apenas essa variável você obtém essa mesmo comportamento, pois quando elas não tiverem nenhum valor definido elas vão assumir por padrão o valor definido em GOPRIVATE.

GOINSECURE

Por padrão a conexão de módulos precisa fazer uso de conexões HTTPS e validar o certificado, o que é ótimo para segurança, mas pode te atrapalhar em desenvolvimento ou até ao fazer uso de alguma PoC.

Essa variável permite você definir valores de servidores que confia para pular a exigência de HTTPS e de certificados válidos. Aqui vale o mesmo cuidado já citado no caso do GONOSUMDB, cuidado ao usar. Em produção, jamais.

Pra fechar

A gente deu uma olhada em algumas das variáveis que o Golang usa internamente, o que vai com certeza ajudar a lidar com problemas de mais baixo nível (como consumir dependências privadas por exemplo), além de aprender um pouco mais do mecanismo de Proxy que é padrão a partir da versão 1.13.

Vou deixar abaixo algumas das referências que eu usei para estudar isso e deixar meu agradecimento para o Fernando Sousa que me ajudou a entender essas variáveis e a galera que fez a revisão do texto.

Referências

Go Modules Reference

Why is GO111MODULE everywhere, and everything about Go Modules

GopherCon 2019: Katie Hockman — Go Module Proxy: Life of a Query

Module Mirror and Checksum Database Launched — The Go Blog

Why you should use a Go module proxy

https://golang.org/cmd/go/#hdr-Module_proxy_protocol

https://proxy.golang.org/

https://sum.golang.org/

--

--

Rogerio Angeliski
Ship It!

Programador Web. Do Back a Front. De Java a JavaScript. De JVM a Node. Do livro ao vídeo game. Nerd as vezes, besta sempre. Falo sério quando não é piada.