Base de Conhecimento

Introdução ao Kubernetes: dicas do kubectl  Imprimir este Artigo

Introdução

O Kubectl é uma ferramenta de linha de comando projetada para gerenciar objetos e clusters do Kubernetes. Ele fornece uma interface de linha de comando para executar operações comuns, como criar e dimensionar implantações, alternar contextos e acessar um shell em um contêiner em execução.

Como usar este guia:

  • Este guia está no formato de folha de dicas com trechos de linha de comando independentes.
  • Não é uma lista exaustiva de comandos kubectl, mas contém muitas operações e casos de uso comuns. Para uma referência mais completa, consulte os Documentos de Referência Kubectl
  • Vá para qualquer seção que seja relevante para a tarefa que você está tentando concluir.

Pré-requisitos

  • Para usar o kubectl, você precisará de um cluster Kubernetes disponível. Para aprender como criar um cluster Kubernetes do zero, você pode consultar Como criar um cluster Kubernetes usando o Kubeadm no Ubuntu 18.04 . Como alternativa, você pode provisionar um cluster Kubernetes gerenciado em minutos usando o DigitalOcean Kubernetes. Para começar a criar um cluster DigitalOcean Kubernetes, consulte Como criar clusters Kubernetes usando o Painel de Controle .
  • Você também precisará de uma máquina remota na qual instalará e executará o kubectl. O kubectl pode ser executado em muitos sistemas operacionais diferentes.

Implantação de amostra

Para demonstrar algumas das operações e comandos nesta folha de dicas, usaremos um exemplo de implantação que executa 2 réplicas do Nginx:

nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

Copie e cole esse manifesto em um arquivo chamado nginx-deployment.yaml.

Instalando o kubectl

Nota: Esses comandos foram testados apenas em uma máquina Ubuntu 18.04 . Para aprender a instalar o kubectl em outros sistemas operacionais, consulte Instalar e configurar o kubectl nos documentos do Kubernetes.

Primeiro, atualize o índice do pacote local e instale as dependências necessárias:

  • sudo apt-get update && sudo apt-get install -y apt-transport-https

Em seguida, adicione a chave GPG do Google Cloud ao APT e disponibilize o pacote kubectl no seu sistema:

  • curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
  • echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
  • sudo apt-get update

Por fim, instale o kubectl:

  • sudo apt-get install -y kubectl

Teste se a instalação foi bem-sucedida usando version:

  • kubectl version

Configurando o preenchimento automático de shell

Nota: Esses comandos foram testados apenas em uma máquina Ubuntu 18.04 . Para saber como configurar o preenchimento automático em outros sistemas operacionais, consulte Instalar e configurar o kubectl nos documentos do Kubernetes.

O kubectl inclui um script de preenchimento automático de shell que você pode disponibilizar para o software de preenchimento automático de shell existente no sistema.

Instalando o preenchimento automático do kubectl

Primeiro, verifique se você possui a conclusão do bash instalada:

  • type _init_completion

Você deve ver alguma saída do script.

Em seguida, sourceo script de preenchimento automático do kubectl no seu ~/.bashrcarquivo:

  • echo 'source <(kubectl completion bash)' >>~/.bashrc
  • . ~/.bashrc

Como alternativa , você pode adicionar o script de conclusão ao /etc/bash_completion.ddiretório:

  • kubectl completion bash >/etc/bash_completion.d/kubectl

Uso

Para usar o recurso de preenchimento automático, pressione a TABtecla para exibir os comandos kubectl disponíveis:

  • kubectl TAB TAB
Output
annotate       apply          autoscale      completion     cordon         delete         drain          explain        kustomize      options        port-forward   rollout        set            uncordon
api-resources  attach         certificate    config         cp             describe
. . .

Você também pode exibir os comandos disponíveis após digitar parcialmente um comando:

  • kubectl d TAB
Output
delete    describe  diff      drain

Conectando, configurando e usando contextos

Conectando

Para testar se o kubectl pode se autenticar e acessar seu cluster Kubernetes, use cluster-info:

  • kubectl cluster-info

Se o kubectl puder se autenticar com êxito no seu cluster, você deverá ver a seguinte saída:

Output
Kubernetes master is running at https://kubernetes_master_endpoint
CoreDNS is running at https://coredns_endpoint

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

O kubectl é configurado usando os arquivos de configuração do kubeconfig . Por padrão, o kubectl procurará um arquivo chamado configno $HOME/.kubediretório Para mudar isso, você pode definir a $KUBECONFIGvariável de ambiente como um arquivo kubeconfig personalizado ou passar o arquivo personalizado no tempo de execução usando o --kubeconfigsinalizador:

  • kubectl cluster-info --kubeconfig=path_to_your_kubeconfig_file

Nota: Se você estiver usando um cluster Kubernetes gerenciado, seu provedor de nuvem deverá ter disponibilizado seu arquivo kubeconfig.

Se você não quiser usar o --kubeconfigsinalizador com todos os comandos e não houver ~/.kube/configarquivo existente , crie um diretório chamado ~/.kubeno diretório inicial, se ele ainda não existir, e copie no arquivo kubeconfig, renomeando-o para config:

  • mkdir ~/.kube
  • cp your_kubeconfig_file ~/.kube/config

Agora, execute cluster-infonovamente para testar sua conexão.

Modificando sua configuração do kubectl

Você também pode modificar sua configuração usando o kubectl configconjunto de comandos.

Para visualizar sua configuração do kubectl, use o viewsubcomando:

  • kubectl config view
Output
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
. . .

Modificando Clusters

Para buscar uma lista de clusters definidos no seu kubeconfig, use get-clusters:

  • kubectl config get-clusters
Output
NAME
do-nyc1-sammy

Para adicionar um cluster à sua configuração, use o set-clustersubcomando:

  • kubectl config set-cluster new_cluster --server=server_address --certificate-authority=path_to_certificate_authority

Para excluir um cluster da sua configuração, use delete-cluster:

Nota: Isso exclui apenas o cluster da sua configuração e não exclui o cluster Kubernetes real.

  • kubectl config delete-cluster

Modificando usuários

Você pode executar operações semelhantes para usuários usando set-credentials:

  • kubectl config set-credentials username --client-certificate=/path/to/cert/file --client-key=/path/to/key/file

Para excluir um usuário da sua configuração, você pode executar unset:

  • kubectl config unset users.username

Contextos

Um contexto no Kubernetes é um objeto que contém um conjunto de parâmetros de acesso para o seu cluster. Ele consiste em um clusternamespaceusertriplo. Os contextos permitem alternar rapidamente entre diferentes conjuntos de configurações de cluster.

Para ver seu contexto atual, você pode usar current-context:

  • kubectl config current-context
Output
do-nyc1-sammy

Para ver uma lista de todos os contextos configurados, execute get-contexts:

  • kubectl config get-contexts
Output
CURRENT   NAME            CLUSTER         AUTHINFO              NAMESPACE
*         do-nyc1-sammy   do-nyc1-sammy   do-nyc1-sammy-admin

Para definir um contexto, use set-context:

  • kubectl config set-context context_name --cluster=cluster_name --user=user_name --namespace=namespace

Você pode alternar entre contextos com use-context:

  • kubectl config use-context context_name
Output
Switched to context "do-nyc1-sammy"

E você pode excluir um contexto com delete-context:

  • kubectl config delete-context context_name

Usando namespaces

Um espaço para nome no Kubernetes é uma abstração que permite subdividir seu cluster em vários clusters virtuais . Usando Namespaces, você pode dividir os recursos de cluster entre várias equipes e objetos de escopo de maneira apropriada. Por exemplo, você pode ter um prodespaço para nome para cargas de trabalho de produção e um devespaço para nome para cargas de trabalho de desenvolvimento e teste.

Para buscar e imprimir uma lista de todos os Namespaces no seu cluster, use get namespace:

  • kubectl get namespace
Output
NAME              STATUS   AGE
default           Active   2d21h
kube-node-lease   Active   2d21h
kube-public       Active   2d21h
kube-system       Active   2d21h

Para definir um espaço para nome para o seu contexto atual, use set-context --current:

  • kubectl config set-context --current --namespace=namespace_name

Para criar um espaço para nome, use create namespace:

  • kubectl create namespace namespace_name
Output
namespace/sammy created

Da mesma forma, para excluir um espaço para nome, use delete namespace:

Aviso: a exclusão de um espaço para nome excluirá tudo no espaço para nome, incluindo a execução de implantações, pods e outras cargas de trabalho. Execute este comando apenas se tiver certeza de que deseja eliminar o que está sendo executado no espaço para nome ou se estiver excluindo um espaço para nome vazio.

  • kubectl delete namespace namespace_name

Para buscar todos os Pods em um determinado espaço para nome ou para executar outras operações nos recursos de um determinado espaço para nome, inclua o --namespacesinalizador:

  • kubectl get pods --namespace=namespace_name

Gerenciando recursos do Kubernetes

Sintaxe geral

A sintaxe geral para a maioria dos comandos de gerenciamento do kubectl é:

  • kubectl command type name flags

Onde

  • command é uma operação que você gostaria de executar, como create
  • type é o tipo de recurso Kubernetes, como deployment
  • name é o nome do recurso, como app_frontend
  • flags existem sinalizadores opcionais que você gostaria de incluir

Por exemplo, o comando a seguir recupera informações sobre uma implantação chamada app_frontend:

  • kubectl get deployment app_frontend

Gestão Declarativa e kubectl apply

A abordagem recomendada para gerenciar cargas de trabalho no Kubernetes é confiar no design declarativo do cluster o máximo possível. Isso significa que, em vez de executar uma série de comandos para criar, atualizar, excluir e reiniciar a execução de Pods, você deve definir as cargas de trabalho, serviços e sistemas que deseja executar nos arquivos de manifesto YAML e fornecer esses arquivos ao Kubernetes, que cuidará do resto.

Na prática, isso significa usar o kubectl applycomando, que aplica uma configuração específica a um determinado recurso. Se o recurso de destino não existir, o Kubernetes criará o recurso. Se o recurso já existir, o Kubernetes salvará a revisão atual e atualizará o recurso de acordo com a nova configuração. Este declarativa abordagem existe em contraste com o imperativo abordagem de executar o kubectl createkubectl edite o kubectl scaleconjunto de comandos para gerir os recursos. Para saber mais sobre as diferentes maneiras de gerenciar recursos do Kubernetes, consulte Gerenciamento de objetos do Kubernetes nos documentos do Kubernetes.

Implementando uma implantação

Por exemplo, para implantar a amostra do Nginx Deployment em seu cluster, use applye forneça o caminho para o nginx-deployment.yamlarquivo de manifesto:

  • kubectl apply -f nginx-deployment.yaml
Output
deployment.apps/nginx-deployment created

-fsinalizador é usado para especificar um nome de arquivo ou URL contendo uma configuração válida. Se você quiser applytodos os manifestos de um diretório, use o -ksinalizador:

  • kubectl apply -k manifests_dir

Você pode acompanhar o status da implementação usando rollout status:

  • kubectl rollout status deployment/nginx-deployment
Output
Waiting for deployment "nginx-deployment" rollout to finish: 1 of 2 updated replicas are available...
deployment "nginx-deployment" successfully rolled out

Uma alternativa rollout statusé o kubectl getcomando, junto com o -wsinalizador (watch):

  • kubectl get deployment -w
Output
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   0/2     2            0           3s
nginx-deployment   1/2     2            1           3s
nginx-deployment   2/2     2            2           3s

Usando rollout pauserollout resume, você pode pausar e retomar a distribuição de uma Implantação:

  • kubectl rollout pause deployment/nginx-deployment
Output
deployment.extensions/nginx-deployment paused
  • kubectl rollout resume deployment/nginx-deployment
Output
deployment.extensions/nginx-deployment resumed

Modificando uma implantação em execução

Se você desejar modificar uma Implantação em execução, poderá fazer alterações no arquivo de manifesto e, em seguida, executar kubectl applynovamente para aplicar a atualização. Por exemplo, modificaremos o nginx-deployment.yamlarquivo para alterar o número de réplicas de 2para 3:

nginx-deployment.yaml
. . .
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
. . .

kubectl diffcomando permite que você veja uma diferença entre os recursos em execução no momento e as alterações propostas no arquivo de configuração fornecido:

  • kubectl diff -f nginx-deployment.yaml

Agora permita que o Kubernetes execute a atualização usando apply:

  • kubectl apply -f nginx-deployment.yaml

A execução de outra get deploymentdeve confirmar a adição de uma terceira réplica.

Se você executar applynovamente sem modificar o arquivo de manifesto, o Kubernetes detectará que nenhuma alteração foi feita e não executará nenhuma ação.

Usando rollout historyvocê pode ver uma lista das revisões anteriores da Implantação:

  • kubectl rollout history deployment/nginx-deployment
Output
deployment.extensions/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>

Com rollout undo, você pode reverter uma implantação para qualquer uma das revisões anteriores:

  • kubectl rollout undo deployment/nginx-deployment --to-revision=1

Excluindo uma implantação

Para excluir uma implantação em execução, use kubectl delete:

  • kubectl delete -f nginx-deployment.yaml
Output
deployment.apps "nginx-deployment" deleted

Gerenciamento Imperativo

Você também pode usar um conjunto de comandos imperativos para manipular e gerenciar diretamente os recursos do Kubernetes.

Criando uma implantação

Use createpara criar um objeto a partir de um arquivo, URL ou STDIN. Observe que applydiferentemente , se um objeto com o mesmo nome já existir, a operação falhará. --dry-runsinalizador permite visualizar o resultado da operação sem realizá-la:

  • kubectl create -f nginx-deployment.yaml --dry-run
Output
deployment.apps/nginx-deployment created (dry-run)

Agora podemos criar o objeto:

  • kubectl create -f nginx-deployment.yaml
Output
deployment.apps/nginx-deployment created

Modificando uma implantação em execução

Use scalepara dimensionar o número de réplicas para a implantação de 2 para 4:

  • kubectl scale --replicas=4 deployment/nginx-deployment
Output
deployment.extensions/nginx-deployment scaled

Você pode editar qualquer objeto no local usando kubectl editIsso abrirá o manifesto do objeto no seu editor padrão:

  • kubectl edit deployment/nginx-deployment

Você deve ver o seguinte arquivo de manifesto em seu editor:

nginx-deployment
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: extensions/v1beta1
kind: Deployment
. . . 
spec:
  progressDeadlineSeconds: 600
  replicas: 4
  revisionHistoryLimit: 10
  selector:
    matchLabels:
. . .

Altere o replicasvalor de 4para 2, salve e feche o arquivo.

Agora execute a getpara inspecionar as alterações:

  • kubectl get deployment/nginx-deployment
Output
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           6m40s

Dimensionamos a implantação com êxito de volta para 2 réplicas on-the-fly. Você pode atualizar a maioria dos campos de um objeto do Kubernetes de maneira semelhante.

Outro comando útil para modificar objetos no local é kubectl patchUsando patch, você pode atualizar os campos de um objeto rapidamente, sem precisar abrir seu editor. patchtambém permite atualizações mais complexas com várias estratégias de mesclagem e aplicação de patches. Para saber mais sobre isso, consulte Atualizar objetos da API no local usando o patch kubectl .

O comando a seguir irá corrigir o nginx-deploymentobjeto para atualizar o replicascampo de 2para 4deployé uma abreviação para o deploymentobjeto.

  • kubectl patch deploy nginx-deployment -p '{"spec": {"replicas": 4}}'
Output
deployment.extensions/nginx-deployment patched

Agora podemos inspecionar as alterações:

  • kubectl get deployment/nginx-deployment
Output
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   4/4     4            4           18m

Você também pode criar uma implantação imperativamente usando o runcomando runcriará uma implantação usando uma imagem fornecida como parâmetro:

  • kubectl run nginx-deployment --image=nginx --port=80 --replicas=2

exposecomando permite que você exponha rapidamente uma Implantação em execução com um Serviço Kubernetes, permitindo conexões de fora do cluster Kubernetes:

  • kubectl expose deploy nginx-deployment --type=LoadBalancer --port=80 --name=nginx-svc
Output
service/nginx-svc exposed

Aqui, expusemos a nginx-deploymentimplantação como um serviço LoadBalancer, abrindo a porta 80para o tráfego externo e direcionando-a para a porta do contêiner 80Nós nomeamos o serviço nginx-svcUsando o tipo de Serviço LoadBalancer, um balanceador de carga na nuvem é automaticamente provisionado e configurado pelo Kubernetes. Para obter o endereço IP externo do Serviço, use get:

  • kubectl get svc nginx-svc
Output
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
nginx-svc   LoadBalancer   10.245.26.242   203.0.113.0   80:30153/TCP   22m

Você pode acessar os contêineres Nginx em execução navegando EXTERNAL-IPno seu navegador da web.

Inspecionando cargas de trabalho e depuração

Existem vários comandos que você pode usar para obter mais informações sobre cargas de trabalho em execução no seu cluster.

Inspecionando recursos do Kubernetes

kubectl get busca um determinado recurso do Kubernetes e exibe algumas informações básicas associadas a ele:

  • kubectl get deployment -o wide
Output
NAME               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES   SELECTOR
nginx-deployment   4/4     4            4           29m   nginx        nginx    app=nginx

Como não fornecemos um nome ou espaço para nome da implantação, o kubectl busca todas as implantações no espaço para nome atual. -obandeira fornece informações adicionais como CONTAINERSIMAGES.

Além disso get, você pode usar describepara buscar uma descrição detalhada do recurso e dos recursos associados:

  • kubectl describe deploy nginx-deployment
Output
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Wed, 11 Sep 2019 12:53:42 -0400
Labels:                 run=nginx-deployment
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               run=nginx-deployment
. . . 

O conjunto de informações apresentadas variará dependendo do tipo de recurso. Você também pode usar este comando sem especificar um nome de recurso; nesse caso, as informações serão fornecidas para todos os recursos desse tipo no espaço para nome atual.

explain permite que você puxe rapidamente campos configuráveis ​​para um determinado tipo de recurso:

  • kubectl explain deployment.spec

Ao adicionar campos adicionais, você pode mergulhar mais fundo na hierarquia de campos:

  • kubectl explain deployment.spec.template.spec

Obtendo acesso do shell a um contêiner

Para obter acesso ao shell em um contêiner em execução, use execPrimeiro, encontre o Pod que contém o contêiner em execução ao qual você deseja acessar:

  • kubectl get pod
Output
nginx-deployment-8859878f8-7gfw9   1/1     Running   0          109m
nginx-deployment-8859878f8-z7f9q   1/1     Running   0          109m

Vamos execpara o primeiro Pod. Como este Pod tem apenas um contêiner, não precisamos usar o -csinalizador para especificar em qual contêiner gostaríamos exec.

  • kubectl exec -i -t nginx-deployment-8859878f8-7gfw9 -- /bin/bash
Output
root@nginx-deployment-8859878f8-7gfw9:/#

Agora você tem acesso ao shell do contêiner Nginx. -ibandeira passa STDIN para o contêiner e -tfornece um TTY interativo. -- traço duplo atua como um separador para o kubectlcomando e o comando que você deseja executar dentro do contêiner. Nesse caso, estamos executando /bin/bash.

Para executar comandos dentro do recipiente sem abrir um shell completo, omitir os -i-tbandeiras, e substituir o comando que você gostaria de executar em vez de /bin/bash:

  • kubectl exec nginx-deployment-8859878f8-7gfw9 ls
Output
bin
boot
dev
etc
home
lib
lib64
media
. . .

Buscando logs

Outro comando útil é o logsque imprime logs de Pods e contêineres, incluindo contêineres finalizados.

Para transmitir logs para a saída do terminal, você pode usar o -fsinalizador:

  • kubectl logs -f nginx-deployment-8859878f8-7gfw9
Output
10.244.2.1 - - [12/Sep/2019:17:21:33 +0000] "GET / HTTP/1.1" 200 612 "-" "203.0.113.0" "-"
2019/09/16 17:21:34 [error] 6#6: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.244.2.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "203.0.113.0", referrer: "http://203.0.113.0"
. . .

Este comando continuará sendo executado no seu terminal até ser interrompido com a CTRL+CVocê pode omitir o -fsinalizador se desejar imprimir a saída do log e sair imediatamente.

Você também pode usar o -psinalizador para buscar logs para um contêiner terminado. Quando essa opção é usada em um Pod que tinha uma instância anterior do contêiner em execução, logsimprimirá a saída do contêiner finalizado:

  • kubectl logs -p nginx-deployment-8859878f8-7gfw9

-csinalizador permite especificar o contêiner do qual você deseja buscar logs, se o Pod tiver vários contêineres. Você pode usar o --all-containers=truesinalizador para buscar logs de todos os contêineres no Pod.

Encaminhamento de porta e proxy

Para obter acesso de rede a um Pod, você pode usar port-forward:

  • sudo kubectl port-forward pod/nginx-deployment-8859878f8-7gfw9 80:80
Output
Forwarding from 127.0.0.1:80 -> 80
Forwarding from [::1]:80 -> 80

Nesse caso, usamos sudoporque a porta local 80é uma porta protegida. Para a maioria das outras portas, você pode omitir sudoe executar o comando kubectl como usuário do sistema.

Aqui encaminhamos a porta local 80(antes dos dois pontos) para a porta do contêiner do Pod 80(após os dois pontos).

Você também pode usar deploy/nginx-deploymentcomo tipo e nome do recurso para o qual encaminhar. Se você fizer isso, a porta local será encaminhada para o Pod selecionado pela Implantação.

proxycomando pode ser usado para acessar o servidor da API Kubernetes localmente:

  • kubectl proxy --port=8080
Output
Starting to serve on 127.0.0.1:8080

Em outro shell, use curlpara explorar a API:

curl http://localhost:8080/api/
Output
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "203.0.113.0:443"
    }
  ]

Feche o proxy pressionando CTRL-C.

Conclusão

Este guia aborda alguns dos comandos mais comuns do kubectl que você pode usar ao gerenciar um cluster Kubernetes e as cargas de trabalho implantadas nele.

Você pode aprender mais sobre o kubectl consultando a documentação de referência oficial do Kubernetes .

Existem muitos outros comandos e variações que você pode achar úteis como parte do seu trabalho com o kubectl. Para saber mais sobre todas as opções disponíveis, você pode executar:

kubectl --help

Esta resposta lhe foi útil?

Veja também

Como criar e instalar programas Go
Introdução Até o momento, em nossa série Como codificar no Go , você usou o comando go runpara...
Tutorial de como instalar Apache, PHP e MySQL
1º Passo - Instalação MySQL # Entre em seu Servidor via SSH e digite:  yum install mysql...
Compreendendo os tipos de dados no Python 3
Introdução No Python, como em todas as linguagens de programação, os tipos de dados são usados...
Como instalar o Webmin no Debian 10
Introdução O Webmin é um painel de controle da web moderno que permite administrar o servidor...
Criando erros personalizados no Go
Introdução Go fornece dois métodos para criar erros na biblioteca padrão errors.Newefmt.Errorf ....