Como obter o endereço IP de um contêiner Docker do host


1412

Existe um comando que eu possa executar para obter o endereço IP do contêiner diretamente do host após a criação de um novo contêiner?

Basicamente, quando o Docker cria o contêiner, desejo rolar meus próprios scripts de implantação de código e configuração de contêiner.


28
Eu só queria garantir que outros noobs não cometessem meu erro e tentassem obter o IP da imagem em vez do contêiner. Certifique-se de obter o CID ou o ID do contêiner e consulte-o; CID via 'docker ps', ou seja.
Paul Gregoire

Como obter vice-versa? IP do host ou chamada do contêiner?
Somnath Muluk

Respostas:


2331

A --formatopção de inspectvem para o resgate.

A sintaxe do cliente Docker moderno é:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id

A sintaxe do cliente Old Docker é:

docker inspect --format '{{ .NetworkSettings.IPAddress }}' container_name_or_id

Esses comandos retornarão o endereço IP do contêiner do Docker.

Conforme mencionado nos comentários: se você estiver no Windows, use aspas duplas, em "vez de aspas simples, 'entre as chaves.


34
Esta é uma solução MUITO melhor. Peça apenas o que você precisa, se possível!
precisa saber é o seguinte

8
Hmm. Conseguir um <no value>resposta em um Mac usando Fig / Boot2Docker
cevaris

2
@cevaris Você obterá <no value>se tentar executar isso em um contêiner que não está sendo executado. Verifique se o contêiner está em execução antes de fazer isso.
TheJediCowboy

55
!ATENÇÃO! Isso não funciona mais. O novo formato é específico para o contêiner e segue o formulário {{ .NetworkSettings.Networks.$network.IPAddress }}. O padrão parece ser bridge, mas em docker-compose, este será um nome específico que depende do nome do seu aplicativo (acho que do sinalizador --project-name, embora isso também dependa de que tipo de configuração de rede você configurou). Eu escrevi uma resposta completa em uma resposta aqui stackoverflow.com/questions/17157721/…
Dunk

5
Talvez eu seja uma ovelha sonolenta, mas o aviso sobre aspas duplas não foi ousado e cintilante o suficiente para chamar minha atenção. Talvez forneça dois exemplos claramente identificados como Linux e Windows. Eu literalmente digitei o exemplo, verifiquei os documentos que também usam aspas simples e depois pesquisei o erro no Google. Tenho certeza de que não estou sozinha.
21719 Wyck

513

Você pode usar docker inspect <container id>.

Por exemplo:

CID=$(docker run -d -p 4321 base nc -lk 4321);
docker inspect $CID

67
A fim de extrair o ip, você pode fazer algo como docker inspect $CID | grep IPAddress | cut -d '"' -f 4, ele funciona bem :)
creack

9
Juntando tudo, este alias shell deve listar todas as identificações de recipiente e seus ips:alias dockerip='docker ps | tail -n +2 | while read cid b; do echo -n "$cid\t"; docker inspect $cid | grep IPAddress | cut -d \" -f 4; done'
ko-dos

64
Conforme mencionado por @ user3119830, há uma nova opção para inspecionar. Agora, você pode facilitar o IP comdocker inspect -format '{{ .NetworkSettings.IPAddress }}' ${CID}
creack

16
Apenas uma nota. As opções de traço único estão sendo descontinuadas para que -format se torne --format.
jamtur01

7
docker inspect -format '{{ .NetworkSettings.IPAddress }}' ${CID}é a nova sintaxe. -formaté preterido, torna-se --format.
Devy

408

Primeiro, obtenha o ID do contêiner:

docker ps

(A primeira coluna é para o ID do contêiner)

Use o ID do contêiner para executar:

docker inspect <container ID>

Na parte inferior, em "Configurações de rede", você pode encontrar "Endereço IP"

Ou faça:

docker inspect <container id> | grep "IPAddress"

5
Pena que, em uma das minhas instâncias (iniciada com docker run -it MYCONTAINER /bin/bash), a saída de inspectnão tem seção NetworkSettings!
Eric

3
Isso não funciona no Windows 10. Você também precisa descobrir o endereço IP do DockerNAT com o ipconfig.
Ntiedt 7/11

@Eric Você também pode inspecionar a ponte de rede para isso:docker network inspect bridge | grep Gateway | grep -o -E '[0-9.]+'
Tomasz Kapłoński

5
Eu prefiro muito a ... | grep IPsolução a todos os detalhes de formatação necessários para obter o IP. 1
d8aninja 6/03/19

1
@ Eric - você confundiu contêiner com imagem . O comando é realmente docker run -it MYIMAGE(que não é um nome de contêiner ); se você docker inspect MYIMAGEobtiver informações estáticas sobre a imagem . Você precisa encontrar o nome do contêiner em execução (ou usar seu ID, como outros sugerem). No meu sistema, o primeiro container criado a partir dessa imagem é padronizado como nome MYIMAGE_1, assim docker inspect MYIMAGE_1como NetworkSettings.
Home

216
docker inspect CONTAINER_ID | grep "IPAddress"

Você pode adicionar -iao grep por ignorar o caso, e até o seguinte funcionará:

docker inspect CONTAINER_ID | grep -i "IPaDDreSS"

5
como esta resposta é melhor / diferente das outras 22?
sds

Definitivamente, essa não é a melhor resposta. A resposta do WouterD é a resposta que você está procurando.
M.Vanderlee

7
@ M.Vanderlee, esta resposta tem um comando que é mais fácil de lembrar, o que a torna uma resposta melhor à IMO.
precisa saber é o seguinte

1
@WouterHuysentruit Claro, mas você recebe várias entradas e o texto "IPAddress" real. Você não pode usá-lo em um script sem manipulação adicional.
M.Vanderlee

Você está certo. No contexto da pergunta, a outra resposta se encaixa melhor.
huysentruitw

133

Para obter todos os nomes de contêineres e seus endereços IP em apenas um único comando.

docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' $(docker ps -aq)

Se você estiver usando docker-composeo comando será este:

docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

A saída será:

/containerA - 172.17.0.4
/containerB - 172.17.0.3
/containerC - 172.17.0.2

5
Eu realmente gosto disso, mas também não funciona para o Docker Compose, algo a ver com ter sua própria rede. Em vez disso, mude {{.NetworkSettings.IPAddress }}para{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}
clockworkgeek

Aqui está o uso variação I: docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -aq | xargs) | sed -e '/^$/d'. Os sed(1)Remove as linhas vazias de recipientes presentes, mas não possuindo um endereço de IP.
NYCeyes

97

Adicione este script de shell no seu ~/.bashrcarquivo ou relevante:

docker-ip() {
  docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$@"
}

Em seguida, para obter o endereço IP de um contêiner, basta fazer o seguinte:

docker-ip YOUR_CONTAINER_ID

Para a nova versão do Docker, use o seguinte:

docker-ip() {
        docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$@"
}

5
Template parsing error: template: :1:19: executing "" at <.NetworkSettings.IPA...>: map has no entry for key "NetworkSettings"
saiyancoder

isso funciona para mim, mas precisasource ~/.bash_profile
centavo chan

1
Você receberá este erro se você não está inspecionando um recipiente em execução, mas apenas uma imagem ... uma imagem não tem um endereço IP ... terrível mensagem de erro, sim
dagelf

37

Mostrar todos os endereços IP do contêiner:

docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

37

No Docker 1.3+, você também pode verificá-lo usando:

Digite o Docker em execução (Linux):

docker exec [container-id or container-name] cat /etc/hosts
172.17.0.26 d8bc98fa4088
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.17 mysql

Para Windows:

docker exec [container-id or container-name] ipconfig

1
ou apenasdocker exec [container-name-or-id] ip a
Stephan Richter

para windowsdocker exec [container-id or container-name] ipconfig
GreatAndPowerfulOz 26/06/19

27

No Docker versão 1.10.3, compilação 20f81dd

A menos que você tenha informado o contrário, o Docker sempre lança seus contêineres na rede de pontes. Então você pode tentar este comando abaixo:

docker network inspect bridge

O qual deve retornar uma seção Contêineres que exibirá o endereço IP desse contêiner em execução.

[
    {
        "Name": "bridge",
        "Id": "40561e7d29a08b2eb81fe7b02736f44da6c0daae54ca3486f75bfa81c83507a0",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16"
                }
            ]
        },
        "Containers": {
            "025d191991083e21761eb5a56729f61d7c5612a520269e548d0136e084ecd32a": {
                "Name": "drunk_leavitt",
                "EndpointID": "9f6f630a1743bd9184f30b37795590f13d87299fe39c8969294c8a353a8c97b3",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        }
    }
]

o que significa se a seção de contêineres está vazia? No entanto, o contêiner está funcionando.
StackEdd

24

Executar:

docker ps -a

Isso exibirá imagens ativas do docker:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                       PORTS               NAMES
3b733ae18c1c        parzee/database     "/usr/lib/postgresql/"   6 minutes ago       Up 6 minutes                 5432/tcp            serene_babbage

Use o valor ID do CONTAINER:

docker inspect <CONTAINER ID> | grep -w "IPAddress" | awk '{ print $2 }' | head -n 1 | cut -d "," -f1

"172.17.0.2"


23

Com base em algumas das respostas que adorei, decidi mesclá-las a uma função para obter todos os endereços IP e outra para um contêiner específico. Eles estão agora no meu .bashrcarquivo.

docker-ips() {
    docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)
}

docker-ip() {
  docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$@"
}

O primeiro comando fornece o endereço IP de todos os contêineres e o segundo endereço IP de um contêiner específico.

docker-ips
docker-ip YOUR_CONTAINER_ID

16

Contêineres de referência por nome:

docker run ... --name pg-master

Em seguida, pegue o endereço do endereço IP pelo nome:

MASTER_HOST=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' pg-master)

15

Eu escrevi o seguinte script Bash para obter uma tabela de endereços IP de todos os contêineres em execução docker-compose.

function docker_container_names() {
    docker ps -a --format "{{.Names}}" | xargs
}

# Get the IP address of a particular container
dip() {
    local network
    network='YOUR-NETWORK-HERE'
    docker inspect --format "{{ .NetworkSettings.Networks.$network.IPAddress }}" "$@"
}

dipall() {
    for container_name in $(docker_container_names);
    do
        local container_ip=$(dip $container_name)
        if [[ -n "$container_ip" ]]; then
            echo $(dip $container_name) " $container_name"
        fi
    done | sort -t . -k 3,3n -k 4,4n
}

Você deve alterar a rede variável para o seu próprio nome de rede.


1
A resposta de Tuong Le aqui stackoverflow.com/questions/17157721/… evita especificar a rede em dip (): docker inspeciona --format '{{range .NetworkSettings.Networks}} {{. IPAddress}} {{end} } '"$ @"
JoanComasFdz

1
@JoanComasFdz você me salvou muito obrigado!
Chagai Friedlander

14

Aqui está uma resposta rápida de trabalho:

Obtenha o nome ou o ID do seu contêiner:

docker container ls

Em seguida, obtenha o IP:

docker inspect <container_ID Or container_name> |grep 'IPAddress'

Obtenha a porta:

docker inspect <container_ID Or container_name> |grep 'Port'

13

O Docker está escrito em Go e também usa a sintaxe Go para fins de consulta.

Para inspecionar o endereço IP de um contêiner específico, você precisa executar o comando ( -fpara "formato"):

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_id_or_name

Para o ID ou nome do contêiner, você pode executar o comando

docker container ls

que listará todos os contêineres em execução.


1
Isso é muito útil. Onde posso encontrar documentação para escrever minhas próprias consultas Go?
Michael Hoffmann

12

Aqui está uma solução que desenvolvi hoje em Python, usando a docker inspect containersaída JSON como fonte de dados.

Eu tenho muitos contêineres e infraestruturas que preciso inspecionar e preciso obter informações básicas de rede de qualquer contêiner, de maneira rápida e bonita . Por isso eu fiz esse script.

IMPORTANTE: Desde a versão 1.9, o Docker permite criar várias redes e anexá-las aos contêineres.

#!/usr/bin/python

import json
import subprocess
import sys

try:
    CONTAINER = sys.argv[1]
except Exception as e:
    print "\n\tSpecify the container name, please."
    print "\t\tEx.:  script.py my_container\n"
    sys.exit(1)

# Inspecting container via Subprocess
proc = subprocess.Popen(["docker","inspect",CONTAINER],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.STDOUT)

out = proc.stdout.read()
json_data = json.loads(out)[0]

net_dict = {}
for network in json_data["NetworkSettings"]["Networks"].keys():
    net_dict['mac_addr']  = json_data["NetworkSettings"]["Networks"][network]["MacAddress"]
    net_dict['ipv4_addr'] = json_data["NetworkSettings"]["Networks"][network]["IPAddress"]
    net_dict['ipv4_net']  = json_data["NetworkSettings"]["Networks"][network]["IPPrefixLen"]
    net_dict['ipv4_gtw']  = json_data["NetworkSettings"]["Networks"][network]["Gateway"]
    net_dict['ipv6_addr'] = json_data["NetworkSettings"]["Networks"][network]["GlobalIPv6Address"]
    net_dict['ipv6_net']  = json_data["NetworkSettings"]["Networks"][network]["GlobalIPv6PrefixLen"]
    net_dict['ipv6_gtw']  = json_data["NetworkSettings"]["Networks"][network]["IPv6Gateway"]
    for item in net_dict:
        if net_dict[item] == "" or net_dict[item] == 0:
            net_dict[item] = "null"
    print "\n[%s]" % network
    print "\n{}{:>13} {:>14}".format(net_dict['mac_addr'],"IP/NETWORK","GATEWAY")
    print "--------------------------------------------"
    print "IPv4 settings:{:>16}/{:<5}  {}".format(net_dict['ipv4_addr'],net_dict['ipv4_net'],net_dict['ipv4_gtw'])
    print "IPv6 settings:{:>16}/{:<5}  {}".format(net_dict['ipv6_addr'],net_dict['ipv6_net'],net_dict['ipv6_gtw'])

A saída é:

$ python docker_netinfo.py debian1

[frontend]

02:42:ac:12:00:02   IP/NETWORK        GATEWAY
--------------------------------------------
IPv4 settings:      172.18.0.2/16     172.18.0.1
IPv6 settings:            null/null   null

[backend]

02:42:ac:13:00:02   IP/NETWORK        GATEWAY
--------------------------------------------
IPv4 settings:      172.19.0.2/16     172.19.0.1
IPv6 settings:            null/null   null

Por favor, mude para python2.7 em um script, python3 está agora em uso comum ou escrever duas versões
42n4

Vou atualizar meu Gist e assim que tiver, vou postar aqui. De fato, este wrapper foi projetado para o Python 2.7. Obrigado pelo feedback!
ivanleoncz

9
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <containername or containerID here>

O procedimento acima funciona se o contêiner for implantado na rede de pontes padrão.

No entanto, se estiver usando uma rede de ponte personalizada ou uma rede de sobreposição, achei o seguinte abaixo para funcionar melhor:

docker exec <containername or containerID here> /sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'

9

Para estender a resposta do ko-dos, aqui está um alias para listar todos os nomes de contêineres e seus endereços IP:

alias docker-ips='docker ps | tail -n +2 | while read -a a; do name=${a[$((${#a[@]}-1))]}; echo -ne "$name\t"; docker inspect $name | grep IPAddress | cut -d \" -f 4; done'

1
Isso pode ser bastante simplificado - use docker ps -qpara evitar o taile --formatpara evitar o grep. Além disso, você pode passar vários IDs de contêiner para docker inspectum loop no shell.
Bryan

1
docker ps -qexibe apenas os IDs numéricos dos contêineres, mas acho que usar o nome deles é melhor. tailé apenas para se livrar da primeira linha (cabeçalho da tabela) e ainda é necessário. Eu poderia usar --format, no entanto: docker ps | tail -n +2 | while read -a a; do name=${a[$((${#a[@]}-1))]}; echo -ne "$name\t"; docker inspect --format="{{.NetworkSettings.IPAddress}}" $name | cut -d \" -f 4; done. Mas isso não parece uma grande melhoria ... a grepIMO era mais legível.
Marco Roy

1
Versão ligeiramente alterada que lista os IPs primeiro, em uma linha, juntamente com o nome do contêiner: docker ps | cauda -n +2 | enquanto lê -aa; do name = $ {a [$ (($ {# a [@]} - 1))]}; docker inspeciona $ name | grep "Endereço IP. * [0-9] \ +" | cut -d \ "-f 4 | tr" \ n "" "; echo -e" \ t $ {name} "; feito
Gilead

Acabou com:docker inspect $cid | grep IPAddress | cut -d '"' -f 4 | tail -n 1
antogerva 25/10

9

Eu uso dessa maneira simples

docker exec -it <container id or name> hostname -i

por exemplo

ubuntu@myhost:~$ docker exec -it 3d618ac670fe hostname -i
10.0.1.5

7

Se você instalou o Docker usando o Docker Toolbox, poderá usar o aplicativo Kitematic para obter o endereço IP do contêiner:

  1. Selecione o container
  2. Clique em Configurações
  3. Clique na guia Portas.

Para mim, o endereço IP estava na guia "Nome do host / portas", mas essa foi uma resposta muito útil! Observe que docker inspectnão funciona quando você executa a caixa de ferramentas da janela de encaixe. Ele informará um endereço IP, mas não é o endereço correto que seus serviços usarão.
Göran Roseen 10/09

7

Para obter o endereço IP e a porta do host de um contêiner:

docker inspect containerId | awk '/IPAddress/ || /HostPort/'

Resultado:

    "HostPort": "4200"
                    "HostPort": "4200"
        "SecondaryIPAddresses": null,
        "IPAddress": "172.17.0.2",
                "IPAddress": "172.17.0.2",

7

NOTA!!! para uso do Docker Compose:

Como o Docker Compose cria uma rede isolada para cada cluster, os métodos abaixo não funcionam docker-compose.


A maneira mais elegante e fácil é definir uma função shell, atualmente a resposta mais votada @ WouterD's :

dockip() {
  docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$@"
}

O Docker pode gravar IDs de contêiner em um arquivo como os programas Linux:

Em execução --cidfile=filename, o Docker despeja o ID do contêiner em "filename".

Consulte " Docker executa a seção equivalente ao PID " para obter mais informações.

--cidfile="app.cid": Write the container ID to the file

Usando um arquivo PID:

  1. Executando contêiner com --cidfileparâmetro, o app.cidconteúdo do arquivo é como:

    a29ac3b9f8aebf66a1ba5989186bd620ea66f1740e9fe6524351e7ace139b909
    
  2. Você pode usar o conteúdo do arquivo para inspecionar os contêineres do Docker:

    blog-v4 git:(develop) ✗ docker inspect `cat app.cid`
    
  3. Você pode extrair o IP do contêiner usando um script Python embutido:

    $ docker inspect `cat app.cid` | python -c "import json;import sys;\
    sys.stdout.write(json.load(sys.stdin)[0]['NetworkSettings']['IPAddress'])"
    172.17.0.2
    

Aqui está uma forma mais humana:

#!/usr/bin/env python
# Coding: utf-8
# Save this file like get-docker-ip.py in a folder that in $PATH
# Run it with
# $ docker inspect <CONTAINER ID> | get-docker-ip.py

import json
import sys

sys.stdout.write(json.load(sys.stdin)[0]['NetworkSettings']['IPAddress'])

Consulte " 10 alternativas para obter os endereços IP do contêiner do Docker " para obter mais informações.


6

Para o Windows 10:

docker inspect --format "{{ .NetworkSettings.IPAddress }}"  containerId

5

Isso listará todos os IPs de contêiner no host:

sudo docker ps -aq | while read line;  do sudo docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $line ; done

5

O Docker inspeciona o uso para imprimir todos os ips de contêiner e seus respectivos nomes

docker ps -q | xargs -n 1 docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} {{ .Name }}' | sed 's/ \// /'

5

Apenas para completar:

Eu realmente gosto da --formatopção, mas no começo eu não estava ciente disso, então usei um simples liner Python para obter o mesmo resultado:

docker inspect <CONTAINER> |python -c 'import json,sys;obj=json.load(sys.stdin);print obj[0]["NetworkSettings"]["IPAddress"]'

Essa é a resposta mais legal. Ver também outra resposta - stackoverflow.com/a/36306632/432903
prayagupd

5

Combinando respostas anteriores com a localização do ID do contêiner com base no nome da imagem do Docker:

docker inspect --format '{{ .NetworkSettings.IPAddress }}' `docker ps | grep $IMAGE_NAME | sed 's/\|/ /' | awk '{print $1}'`

4

Usar:

docker inspect $CID | grep IPAddress | grep -v null| cut -d '"' -f 4 | head -1

Este é o comando apropriado da linha única real. Aqui está o que eu tenho. $ docker inspect c4591485328d | grep IPAddress | grep -v null| cut -d '"' -f 4 | head -1 172.17.0.2
precisa saber é o seguinte

4

Para contêineres do Windows, use

docker exec <container> ipconfig

onde <container>é o nome ou o ID do contêiner.

Você pode usar docker pspara encontrar o ID do contêiner.


Lembre-se de usar “—rm”; caso contrário, ele consumirá lentamente o espaço no disco rígido com camadas não danificadas. É bom parear "- rm" com "executar" em quase todos os casos.
Contango

@ Contango: 'docker exec' executa um comando em um contêiner já em execução. Ele não possui uma opção --rm. docs.docker.com/engine/reference/commandline/exec
kirodge

4

Se você esqueceu a ID do contêiner ou não deseja manipular com os comandos do shell, é melhor usar a interface do usuário como o Portainer.

https://portainer.io/

$ docker volume create portainer_data
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

Lá você pode encontrar todas as informações sobre o contêiner também IP.


4
Embora esse link possa responder à pergunta, apenas as respostas do link são desencorajadas no Stack Overflow, você pode melhorar essa resposta pegando partes vitais do link e colocando-o na sua resposta, isso garante que sua resposta ainda seja uma resposta se o link for alterado ou removido :)
WhatsThePoint 4/17/17
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.