Mudanças entre as edições de "Servidor de Aplicações em Contêineres"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
Linha 575: Linha 575:
  
 
Devido à falta de informações suficientes providas pelo LDAP, não foi possível usar os usuários de rede dos alunos. De maneira a agilizar a criação e remoção de contas, foram criados scripts para realizar essas funções. <br />
 
Devido à falta de informações suficientes providas pelo LDAP, não foi possível usar os usuários de rede dos alunos. De maneira a agilizar a criação e remoção de contas, foram criados scripts para realizar essas funções. <br />
 +
 +
O primeiro passo é mudar para a pasta /home/scripts
 +
cd /home/scripts/
 +
--[[Usuário:Moecke|Marcos Moecke]] 11h10min de 20 de fevereiro de 2018 (-03)
 +
 
Abaixo, a sintaxe de utilização do script de gerência de usuários, que ignora usuários já existentes no sistema, alunos que não retornaram nome e usuário e alunos que retornaram mais de um nome de usuário:
 
Abaixo, a sintaxe de utilização do script de gerência de usuários, que ignora usuários já existentes no sistema, alunos que não retornaram nome e usuário e alunos que retornaram mais de um nome de usuário:
  

Edição das 11h10min de 20 de fevereiro de 2018

A estrutura

  • Máquina virtual (VMWare):
    • Memória RAM: 15672 MB, virtualizado;
    • CPU: Intel(R) Xeon(R) CPU E5-2640 v3 @ 2.60GHz, 8 núcleos virtualizados;
    • Armazenamento: um disco virtual de 20 GB para o sistema operacional de gerência e um disco virtual de 200 GB montado em /var/lib/docker;
  • Sistema Operacional de gerência (instalado em máquina virtual VMWare): Container Linux by CoreOS 1520.8.0 (Ladybug);
    • Versão da distribuição: 1520.8.0;
    • Nome da versão da distribuição: Ladybug;
    • Nome da distribuição: Container Linux by CoreOS;
  • Contêiner Docker com sistema base Debian 8 (Jessie), dispondo das seguintes aplicações:
    • Quartus 13.0sp1 com Modelsim Altera 10.1d;
    • Quartus 16.0 com Modelsim Altera 10.4d;
    • MatLab 2015a;
    • Octave 4.2.1;
    • Omnet++ 5.0;
    • Gdrive;
  • Contêiner Docker com sistema base Debian 9 (Stretch).
    • Aluno responsável: Gustavo Paulo Medeiros da Silva;
    • Professor orientador: Ramon Mayor Martins;
    • Aplicações: Node.js, csdr;
    • Site: IFSC-SDR

O CoreOS

Logomarca do Container Linux by CoreOS

O CoreOS (Container Linux by CoreOS) é um sistema operacional de código aberto voltado à execução de contêineres. Seu objetivo é permitir a execução de aplicações em qualquer ambiente. Fornece ferramentas de gerência de contêineres como Docker e Rocket, que é feito pela mesma equipe que criou o Container Linux. Possui suporte ao Kubernetes, que é uma poderosa ferramenta de gerência de contêineres, baseada na experiência que a Google teve. O CoreOS também tem seu código no GitHub.

Instalação do Container Linux

Para a instalação do CoreOS, baixe a ISO da versão de produção do sistema através deste link. A versão de produção é a mais indicada para ambientes que necessitam de uma maior estabilidade no sistema operacional. Após baixada a ISO, em caso de instalação em uma máquina física, pode-se gravá-la em um pendrive usando o comando "dd", ou outro gravador de imagens em dispositivos de sua preferência, ou realizar o boot diretamente dela, em caso de máquina virtual. Em seguida, dê boot do sistema, que começará a ser carregado e irá concluir em uma tela com o login já feito. Digite sudo su para se tornar root. Neste momento, os sistema está apenas carregado em memória. Antes de instalá-lo, primeiramente a rede deve ser corretamente configurada, já que o script de instalação baixa uma imagem que é o sistema a ser gravado no disco rígido. É possível utilizar o comando "ifconfig", o comando "ip" ou o serviço "systemd-networkd" para a configuração da rede, além do comando "route" para definir o gateway. De modo que a configuração seja mais rápida, optar-se-á pela utilização do comando "ifconfig" para a configuração da rede, como mostrado no exemplo abaixo:

ifconfig eth0 191.36.8.33/27
route add default gw 191.36.8.62
echo "nameserver 8.8.8.8" > /etc/resolv.conf

No uso do comando ifconfig, a interface de rede eth0 foi definida com o endereço IP 191.36.8.33 com máscara de sub-rede 255.255.255.224 ou /27. No uso do comando route, foi definido como roteador principal o endereço IP 191.36.8.62.
No uso do comando echo, foi gravado no arquivo resolv.conf, localizado em /etc, o servidor para a busca de nomes.
Após a configuração de rede, instale o Container Linux utilizando o seguinte script presente em /bin, como no exemplo abaixo:

coreos-install -C stable -d /dev/sda

O script coreos-install está localizado em /bin e é um shell script. Ao utilizar o argumento -C e o parâmetro stable, definiu-se o canal de atualizações bem como o estágio de desenvolvimento da imagem que será baixada, verificada e gravada no HD. O argumento -d vem de device e especifica o dispositivo o qual a imagem baixada será gravada. A identificação do dispositivo pode variar de ambiente para ambiente.
Após isso, reinicie o sistema utilizando o comando reboot. O sistema será rapidamente desligado e ligado novamente, é importante ser rápido quando a tela do grub ↓

Coreos-grub.png

aparecer para que se edite um parâmetro de boot a fim de modificar a senha de usuário.

Coreos-grub2.png

Adicione no final da linha linux$suf $gptprio_kernel $gptprio_cmdline $linux_cmdline o parâmetro init=/bin/bash, como mostrado na imagem abaixo. Lembrando que a disposição do teclado está para inglês estadunidense.

Coreos-grub3.png

Após adicionar o parâmetro no final da linha, pressione a tecla "F10" para dar o boot, que concluir-se-á com uma tela parecida com a imagem abaixo.

Coreos-grub4.png

Digite o comando mount -o remount / a fim de dar permissão de escrita.

Coreos-grub5.png

Agora, mude a senha do usuário "core" utilizando o comando passwd, como mostrado na imagem abaixo:

Coreos-grub6.png

Reinicie o sistema e você já poderá logar com o usuário "core" e a senha que você definiu anteriormente. Para tornar-se root, digite sudo su após estar logado.

Configuração da Rede

A configuração da rede pode dar-se de duas formas, via SystemD ou via Cloud Config. Nesse primeiro momento, será explicada a configuração via SystemD. Para tanto, inicialmente criaremos um arquivo com a extensão .network em /etc/systemd/network.

vi /etc/systemd/network/0-eth0.network

E escreveremos no arquivo as configurações de rede, como no modelo abaixo:

[Match]
Name=eth0

[Network]
DNS=191.36.8.2
Address=191.36.8.33/27
Gateway=191.36.8.62

Agora basta reiniciar o serviço que gerencia a rede:

systemctl restart systemd-networkd

O Docker

Logomarca do Docker

O Container Linux by CoreOS já vem com o Docker. Digitando docker version, obtemos a seguinte saída:

docker version
Client:
 Version:      1.12.6
 API version:  1.24
 Go version:   go1.7.6
 Git commit:   a82d35e
 Built:        Tue Sep  5 20:35:08 2017
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.6
 API version:  1.24
 Go version:   go1.7.6
 Git commit:   a82d35e
 Built:        Tue Sep  5 20:35:08 2017
 OS/Arch:      linux/amd64

Baixando uma imagem base

Para baixar uma imagem de sistema operacional base para um contêiner, digite:

docker pull nome_imagem:tag

Por exemplo, para baixar uma imagem base Debian Stretch:

docker pull debian:stretch

As tags podem ser obtidas no Docker Hub.

Criando um contêiner

Para a criação de um contêiner, utiliza-se o comando docker com o parâmetro run. Observe o exemplo abaixo:

docker run -it debian:stretch

O comando acima já é suficiente para a criação de um contêiner. Caso a imagem especificada não tenha sido baixada anteriormente, o Docker baixa a imagem e logo em seguida cria o contêiner. É possível definir mais parâmetros:

localhost core # docker run ···

-it → assim que o contêiner for criado, entrega ao terminal atual um console tty interativo;
--name=nome_do_conteiner → define o nome do contêiner. Caso este parâmetro seja omitido, o Docker selecionará randomicamente um nome.
--net nome_da_rede → especifica o nome da rede. Caso este parâmetro seja omitido, o Docker associará o contêiner à rede padrão chamada "docker0", de nome "bridge".
--ip <endereço IP> → especifica um endereço IP fixo para o contêiner. Caso este parâmetro seja omitido, o Docker atribuirá um endereço IP seguindo uma sequência em ordem crescente. Salientando que na interface padrão "docker0" NÃO é possível escolher o endereço IP do contêiner, apenas em interfaces criadas pelo usuário, algo que será explicado mais adiante.
-p porta_do_host:porta_do_conteiner → associa uma porta do sistema operacional gerente a uma porta do contêiner. Apesar de prático, este parâmetro bagunça muito as regras do IPTables o que faz com que, ao possuir um grande número de contêineres, fique mais difícil de fazer algum ajuste.
-v /pasta/no/sistema:/pasta/no/conteiner → associa um diretório do sistema operacional gerente a um diretório dentro do contêiner. Também é possível criar volumes.
-h nome_de_host → define o nome de host (hostname) do contêiner.
--privileged → dá ao contêiner acesso a todo o hardware do sistema operacional gerente. É recomendado o uso apenas em casos que realmente necessitem de tal recurso.
--cap-add=habilidade → dá ao contêiner habilidades de gerência como se fosse o sistema operacional gerente. Por exemplo, em caso de --cap-add=NETWORK, permite o contêiner modificar a rede do sistema operacional gerente. Este parâmetro deve ser usado muito cautelosamente.
-d → executa o contêiner em segundo plano.
--dns=endereço_IP → define um servidor DNS para o contêiner.
--dns-search → define o domínio de busca do servidor DNS.
--mac-address=" " → define o endereço MAC do dispositivo de rede do contêiner.
--restart=" " ' → quando definido --restart=always, sempre que o contêiner for interrompido, o Docker reiniciar-lo-á. Caso --restart=on-failure, quando contêiner for finalizado com saída diferente de 0, o Docker reiniciar-lo-á. Caso --restart=on-failure:n, o qual n é um número natural, após n vezes que o contêiner falhar e for reiniciado, o Docker interromperá os reinícios automáticos.
--device=/dev/dispositivo → permite o contêiner utilizar um determinado dispositivo.
-rm → cria um contêiner temporário, assim que o contêiner for parado, ele será automaticamente excluído.

Abaixo, segue um exemplo da criação de um contêiner:

docker run -d --name=Portainer -h portainer -v /var/run/docker.sock:/var/run/docker.sock -v /home/portainer:/data portainer/portainer

O exemplo acima cria um contêiner denominado Portainer, que tem dois pontos de montagem (-v), o primeiro montando o arquvio /var/run/docker.sock do sistema de gerência no arquivo /var/run/docker.sock dentro do contêiner. O segundo ponto de montagem, conecta o diretório /home/portainer do sistema de gerência com o diretório /data do contêiner. Por fim, como último argumento de linha de comando, é dado o nome da imagem, nesse caso portainer/portainer. Com o parâmetro -h,foi definido o nome de host. Note que foi omitida a tag da imagem, quando isso ocorre, é dada a tag latest, que corresponde à última versão da imagem (portainer/portainer:latest).


Outro exemplo:

docker run -it -d --name=servidor-web --net faixa10 --ip 10.10.10.110 -h servidor-web --restart=on-failure:10 --dns=191.36.8.2 --dns-search=sj.ifsc.edu.br --device=/dev/kvm:/dev/kvm --privileged -v /home/servidor-web:/var/www/html debian:jessie

No exemplo acima:

  • É criado um contêiner
    • -it → com tty interativo
    • -d → o contêiner, assim que criado, ficará em execução em segundo plano.
    • --name=servidor-web → o nome do contêiner é servidor-web
    • --net faixa10 → ele está associado à ponte denominada faixa10
    • --ip 10.10.10.110 → o endereço IP do contêiner é 10.10.10.110
    • -h servidor-web → o nome de host do contêiner é servidor-web.
    • --restart=on-failure:10 → o contêiner será reiniciado quando falhar, no entanto, caso ocorram 10 falhas consecutivas, o reinício automático é interrompido.
    • --dns=191.36.8.2 → o servidor de nomes 191.36.8.2 é usado. O endereço pode ser encontrado dentro do arquivo /etc/resolv.conf dentro do contêiner.
    • --dns-search=sj.ifsc.edu.br → o domínio de busca é sj.ifsc.edu.br.
    • --device=/dev/kvm:/dev/kvm → o contêiner terá acesso ao dispositivo de virtualização kvm.
    • --privileged → o contêiner terá permissões para acessar todos os dispositivos devidamente reconhecidos do sistema de gerência.
    • -v /home/servidor-web:/var/www/html → o diretório /home/servidor do sistema de gerência é associado com o diretório /var/www/html do contêiner.
    • debian:jessie → a imagem base utilizada é o Debian na versão Jessie.

Configuração da rede

O Docker trabalha com dispositivos de rede virtuais do tipo ponte, nulo e até mesmo a própria rede do sistema operacional de gerência. Ao ser instalado, ele cria automaticamente a ponte denominada docker0, que dentro do Docker recebe o nome de bridge.
É possível também criar interfaces de rede virtuais através do Docker com o comando docker network create. Por exemplo:

docker network create --driver bridge --subnet=10.10.10.0/24 --gateway=10.10.10.10 --opt "com.docker.network.bridge.name"="faixa10" faixa10

O comando acima manda o Docker criar uma ponte de nome "faixa10" e identificação de "faixa10" no sistema. Note que a ponte "docker0" tem nome de "bridge" no Docker, então, o que é visto no comando ifconfig ou ip é docker0, porém, ao usar o comando docker network ls, que lista as pontes usáveis para o Docker, o nome que aparece não é docker0, mas sim bridge. O último argumento da linha de comando é justamente o nome que aparece no sistema. Afim de tornar o uso da ponte mais prático, recomenda-se utilizar o mesmo nome para ambas identificações. Em resumo:

  • docker network create
    • --driver bridge → a interface de rede é do tipo ponte.
    • --subnet=10.10.10.0/24 → define o tamanho da sub-rede, que neste caso é 255.255.255.0, indo de 10.10.10.1 à 10.10.10.254 na faixa de IPs válidos nesta sub-rede.
    • --gateway=10.10.10.10 → define o endereço IP da ponte. A ponte é o roteador dos contêineres que serão associados à ela.
    • --opt "com.docker.network.bridge.name"="faixa10" → define o nome da ponte dentro do Docker, ou seja, o nome que aparece no comando docker network ls.
    • faixa10 → define o nome da ponte no sistema de gerência, ou seja, o nome que aparece no resultado dos comandos ifconfig ou ip -4 a.

Saída do comando docker network ls:

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
3a2ca6e077dd        DMZ191              bridge              local               
e6105c781cdf        bridge              bridge              local               
44fcf67f5607        faixa10             bridge              local               
0b11f4caff4c        host                host                local               
88354106cf7f        none                null                local

Saída do comando ip -4 a:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
3: DMZ191: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    inet 191.36.8.33/27 scope global DMZ191
       valid_lft forever preferred_lft forever
4: faixa10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    inet 10.10.10.10/24 scope global faixa10
       valid_lft forever preferred_lft forever
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever

Nos comandos acima, é possível ver duas pontes criadas pelo usuário, a faixa10 e a DMZ191. A ponte DMZ191, permite criar contêineres com endereço IP da faixa do sistema de gerência. A ponte DMZ191 foi criada utilizando o comando abaixo:

docker network create --driver bridge --subnet=191.36.8.32/27 --gateway=191.36.8.33 --opt "com.docker.network.bridge.name"="DMZ191" DMZ191

No comando acima temos:

  • docker network create
    • --driver bridge → interface de rede do tipo ponte;
    • --subnet=191.36.8.32/27 → define o tamanho da sub-rede, que neste caso é 255.255.255.224, indo de 191.36.8.33 à 191.36.8.62 na faixa de IPs válidos nesta sub-rede.
    • --gateway=191.36.8.33 → define o endereço IP da ponte que, nesse caso, é o endereço IP do servidor em si.
    • --opt "com.docker.network.bridge.name"="DMZ191" → define o nome da ponte dentro do Docker, ou seja, o nome que aparece no comando docker network ls.
    • DMZ191 → define o nome da ponte no sistema de gerência, ou seja, o nome que aparece no resultado dos comandos ifconfig ou ip -4 a.

Após criada a ponte com o IP da faixa do host, basta adicionar a interface física do host na ponte através do comando abaixo:

brctl addif DMZ191 nome_da_interface

Por exemplo:

brctl addif DMZ191 ens33

E a saída do comando brctl show deve ficar assim:

brctl show
bridge name	bridge id		STP enabled	interfaces
DMZ191		8000.000c297ca02d	no		ens33

Caso o sistema de gerência esteja sendo executado em uma máquina virtual, o virtualizador DEVE pemitir que a interface entre em MODO PROMÍSCUO. No virtualizador que bloqueia o modo promíscuo, os pacotes são derrubados pois é impedido que dois endereços MAC (o da ponte, que contém o endereço IP, e o da interface, que faz a conexão externa) solicitem o mesmo pacote.

O exemplo abaixo cria um contêiner com endereço IP da mesma faixa do servidor o qual o contêiner ficará hospedado:

docker run -it -d --name=conteiner-dmz --net DMZ191 --ip 191.36.8.50 -h conteiner-dmz debian:jessie

No exemplo acima temos um contêiner de nome conteiner-dmz, que está associado à ponte DMZ191, possui endereço IP 191.36.8.150, nome de host conteiner-dmz, e usa a imagem do debian:jessie como base.
No entanto, se o sistema operacional de gerência for reiniciado, todas as configurações de ponte, como associação da interface de rede física na ponte que permite criar contêineres na faixa de endereços IP do host. Para tornar esse processo automatizado, basta criar um serviço do SystemD em /etc/systemd/system, que, neste exemplo, será chamado de ponte-roteador-DMZ1.service:

vi /etc/systemd/system/ponte-roteador-DMZ191.service

E adicionar o seguinte conteúdo ao arquivo:

[Unit]
Description=Faz as configuracoes de rede compartilhada DMZ191
After=systemd-networkd.service docker.service
Requires=systemd-networkd.service

[Service]
Type=oneshot
ExecStartPre=/bin/sleep 10
ExecStart=/sbin/brctl addif DMZ191 ens33 ; /bin/route add default gw 191.36.8.62

[Install]
WantedBy=multi-user.target

No exemplo de serviço acima, são executados três comandos:

  • sleep 10 → realiza uma contagem de 10 segundos;
  • brctl addif DMZ191 ens33 → Adiciona a interface ens33 na ponte DMZ191;
  • route add default gw 191.36.8.62 → define o endereço IP 191.36.8.62 como roteador;

Para que esse serviço seja iniciado automaticamente durante o início do sistema operacional, digite:

systemctl enable ponte-roteador-DMZ191.service

É possível verificar se o início automático do serviço foi ativado com o seguinte comando:

systemctl status ponte-roteador-DMZ191

O comando acima retornará uma saída semelhante à saída parcial abaixo:

● ponte-roteador-DMZ191.service - Faz as configuracoes de rede compartilhada DMZ191
   Loaded: loaded (/etc/systemd/system/ponte-roteador-DMZ191.service; enabled; vendor preset: disabled)

A bandeira "enabled" presente na segunda linha da saída do comando "systemctl status ponte-roteador-DMZ191" indica que o início automático do serviço foi ativado.

Arquivo com as regras do IPTables

Para gerenciar as regras no IPTables, é possível utilizar um aquivo contendo essas regras. É possível usar o modelo abaixo para começar um arquivo de regras do IPTables:

# Generated by iptables-save v1.4.21 on Mon Jul 24 10:08:01 2017
*mangle
:PREROUTING ACCEPT [598596665:677097829571]
:INPUT ACCEPT [174957:66070167]
:FORWARD ACCEPT [599651413:677110534191]
:OUTPUT ACCEPT [17908:3643447]
:POSTROUTING ACCEPT [599669321:677114177638]
COMMIT
# Completed on Mon Jul 24 10:08:01 2017
# Generated by iptables-save v1.4.21 on Mon Jul 24 10:08:01 2017
*nat
:PREROUTING ACCEPT [477675:28199468]
:INPUT ACCEPT [673:193661]
:OUTPUT ACCEPT [375:26498]
:POSTROUTING ACCEPT [10042:607734]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER

################## Redirecionamentos de porta ####################



##################################################################

-A POSTROUTING -s 10.10.10.0/24 ! -o faixa10 -j MASQUERADE
-A POSTROUTING -s 192.168.16.0/24 ! -o faixa192 -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

COMMIT
# Completed on Mon Jul 24 10:08:01 2017
# Generated by iptables-save v1.4.21 on Mon Jul 24 10:08:01 2017
*filter
:INPUT ACCEPT [176787:66261039]
:FORWARD ACCEPT [603170623:680968865198]
:OUTPUT ACCEPT [18726:3730253]
:DOCKER - [0:0]
:DOCKER-ISOLATION - [0:0]

COMMIT
# Completed on Mon Jul 24 10:08:01 2017

Salvando o modelo acima em um arquivo, basta adicionar os redirecionamentos, como explicado logo abaixo.
Para aplicar as novas regras, basta utilizar o comando iptables-restore:

iptables-restore arquivo_com_as_regras

Redirecionamento de Portas

O arquivo regras-iptables presente no diretório /home, neste caso, refere-se a um caso particular deste servidor, ou seja, para outros casos, este arquivo deve ser criado manualmente pelo usuário, podendo ficar em qualquer lugar do sistema de arquivos acessível pelo IPTables.
Para fazer o redirecionamento de uma porta do contêiner para o sistema de gerência e vice-versa, basta adicionar uma regra no arquivo regras-iptables presente no diretório /home. Abaixo, um exemplo:

→ Redirecionando apenas uma porta:

-A PREROUTING -d 191.36.8.33/32 -p tcp -m tcp --dport PORTA_DO_IP_EXTERNO -j DNAT --to-destination IP_DO_CONTÊINER:PORTA_DO_CONTÊINER

-A PREROUTING -d 191.36.8.33/32 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.10.10.200:80

No exemplo acima, a porta externa 443 foi redirecionada para a porta 80 do contêiner de endereço IP 10.10.10.200.

→ Redirecionando uma faixa de portas:

-A PREROUTING -d 191.36.8.33/32 -p tcp -m tcp --dport FAIXA_DE_PORTAS_EXTERNAS -j DNAT --to-destination IP_DO_CONTÊINER:FAIXA_DE_PORTAS_DO_CONTÊINER

-A PREROUTING -d 191.36.8.33/32 -p tcp -m tcp --dport 10000:20000 -j DNAT --to-destination 10.10.10.150:10000-20000

No exemplo acima, a faixa de portas externa 10000:20000 foi redirecionada para a faixa de portas 10000:20000 do contêiner de endereço IP 10.10.10.150.
A faixa de portas externas deve ter a mesma quantidade de portas que a faixa de portas do contêiner e as portas devem ser correspondentes, ou seja, as faixas devem ter as mesmas portas..
O argumento -p bagunça demasiadamente as regras do IPTables, criando três regras para cada redirecionamento.
Para aplicar as novas regras, basta utilizar o comando iptables-restore:

iptables-restore arquivo_com_as_regras

Automatização da aplicação das regras do IPTables via arquivo

Para automatizar o processo de aplicação das regras do IPtables é possível criar um serviço do SystemD para isso. Por exemplo, basta criar um arquivo em /etc/systemd/system chamado 'iptables-restore.service, como no modelo abaixo:

[Unit]
Description=Aplica regras no firewall
After=multi-user.target

[Service]
Type=simple
ExecStartPre=/usr/bin/sleep 15
ExecStart=/sbin/iptables-restore /var/lib/docker/home-conteiner/quartus-matlab/regras-iptables

[Install]
WantedBy=custom.target

O nome do arquivo .service é de livre escolha do usuário desde que não contenha caracteres inválidos.
Após criado, basta ativar o serviço:

systemctl enable iptables-restore

Depois de ativado, o serviço iniciar-se-á no boot do sistema operacional. Para iniciar o serviço imediatamente:

systemctl start iptables-restore

Aplicando as regras do IPTables via arquivo em intervalos de tempo

Para aplicar as regras do IPTables em intervalos de tempo, basta usar o temporizador do SystemD para isso. Para tanto, deve ser criado um aquivo .timer contendo o mesmo nome do arquivo .service, que neste caso ficaria iptables-restore.timer, como mostrado no exemplo abaixo:

vi /etc/systemd/system/iptables-restore.timer

E adicionando um conteúdo, como no modelo abaixo:

[Unit]
Description=Executar o serviço itables-restore.service a cada 1 miuto

[Timer]
OnBootSec=20
OnUnitActiveSec=1min

[Install]
WantedBy=multi-user.target

O temporizador definido acima ativa o serviço iptables-restore.service a cada 1 minuto, reaplicando as regras do IPTables definidas em um arquivo.
Após criado, basta ativá-lo:

systemctl enable iptables-restore.timer

Após ativo, o temporizador iniciar-se-á em cada boot do sistema operacional. Para iniciar o temporizador imediatamente:

systemctl start iptables-restore.timer

Scripts para gerência de usuários

Devido à falta de informações suficientes providas pelo LDAP, não foi possível usar os usuários de rede dos alunos. De maneira a agilizar a criação e remoção de contas, foram criados scripts para realizar essas funções.

O primeiro passo é mudar para a pasta /home/scripts
cd /home/scripts/
--Marcos Moecke 11h10min de 20 de fevereiro de 2018 (-03)

Abaixo, a sintaxe de utilização do script de gerência de usuários, que ignora usuários já existentes no sistema, alunos que não retornaram nome e usuário e alunos que retornaram mais de um nome de usuário:

root@quartus-matlab:/# usuarios lista

No comando acima, o script obtém o nome completo dos usuário a partir do arquivo "lista". A lista com a matrícula, nome completo dos usuários, curso, e a situação dos usuários (M = matriculado, C = cancelado, A = aprovado, T = trancado), tem o formato CSV (comma separated value), como no exemplo abaixo:

MATRÍCULA,NOME,SOBRENOME,curso,estado
123456789-0,MARIO,DE ANDRADE,Engenharia de Telecomunicações,M
246801357-9,JOAO,VITOR DOS PASSOS,Química,C

Abaixo, o script de gerência dos usuários:

#!/bin/bash

FILE=$1
verificar=$(cut -d: -f1 /etc/passwd)

rm -r /var/log/usuarios
mkdir /var/log/usuarios

while IFS=, read -r matricula nome sobrenome curso estado
do
  echo "Usuario $nome $sobrenome de matricula $matricula"
  ldap=$(ldapsearch -h 191.36.8.12 -b "dc=cefetsc,dc=edu,dc=br" -x "(&(cn=$nome)(sn=$sobrenome))"  | grep uid: |cut -f2 -d " ")
  usuariolocal=$(echo "$verificar" |grep -w "^$ldap")
  nomelocal=$(cut -d ":" -f5 /etc/passwd |cut -d "," -f1 |grep -w "^$nome $sobrenome")
  contagem=$(echo "$ldap" |wc -l)
  # pasta=$(ls /home/alunos/$ldap)

  ##################### Verificação #####################
  if [ -z "${1}" ]; then
    echo "Não foi provida nenhuma informação!"
    echo "Sintaxe de uso: criar-usuarios lista curso"

  ##################### Manipulação de usuários #####################

  ##################### Usuários cancelados #####################

  elif [ "$estado" = "C" ]; then
    echo "Usuário $nome $sobrenome marcado como cancelado."
    if [ "$nomelocal" = "$nome $sobrenome" ]; then
      echo "O usuário está registrado no sistema."
      pasta=$(ls /home/alunos/$usuariolocal)
      if [ -z "${pasta}" ]; then
        echo "Usuário $usuariolocal foi excluído bem como sua pasta pois a esta estava vazia."
        echo ""
        echo "Nome: $nome $sobrenome" >> /var/log/usuarios/cancelados.log
        echo "Matrícula: $matricula" >>  /var/log/usuarios/cancelados.log
        echo "Nome de usuário: $usuariolocal" >> /var/log/usuarios/cancelados.log
        echo "Situação: o usuário bem como sua pasta foram excluídos." >> /var/log/usuarios/cancelados.log
        echo "" >> /var/log/usuarios/cancelados.log
        userdel -r $usuariolocal

      else

        echo "O usuário $usuariolocal está com o estado de cancelado, no entanto sua pasta de usuário não estava vazia, por isso não foi excluída."
        echo ""
        echo "Nome: $nome $sobrenome" >> /var/log/usuarios/cancelados.log
        echo "Matrícula: $matricula" >>  /var/log/usuarios/cancelados.log
        echo "Nome de usuário: $usuariolocal" >> /var/log/usuarios/cancelados.log
        echo "Situação: o usuário não foi excluído porque sua pasta não estava vazia." >> /var/log/usuarios/cancelados.log
        echo "" >> /var/log/usuarios/cancelados.log
  
      fi
    
    else

      echo "O usuário $nome $sobrenome não estava cadastrado."
      echo ""
      echo "Nome: $nome $sobrenome" >> /var/log/usuarios/cancelados.log
      echo "Matrícula: $matricula" >>  /var/log/usuarios/cancelados.log
      echo "Situação: o usuário não foi excluído porque não estava cadastrado." >> /var/log/usuarios/cancelados.log
      echo "" >> /var/log/usuarios/cancelados.log

    fi

  ##################### Usuários matriculados #####################

  elif [ "$estado" = "M" ]; then

    if [ "$nomelocal" = "$nome $sobrenome" ]; then
 
      echo "O usuário $usuariolocal já existe no sistema!."
      echo ""
      echo "Nome completo: $nome $sobrenome" >> /var/log/usuarios/existentes.log
      echo "Matrícula: $matricula" >> /var/log/usuarios/existentes.log
      echo "Nome de usuário: $ldap" >> /var/log/usuarios/existentes.log
      echo "" >> /var/log/usuarios/existentes.log
  
    elif [ -z "${ldap}" ]; then
      echo "O usuário não foi encontrado através critério de busca utilizado."
      echo " "
      echo "Nome: $nome $sobrenome" >> /var/log/usuarios/erro.log
      echo "Matrícula: $matricula" >>  /var/log/usuarios/erro.log
      echo "Erro: O usuário não foi encontrado através dritério d busca utilizado." >> /var/log/usuarios/erro.log
      echo "" >> /var/log/usuarios/erro.log
  
    elif (( "$contagem" > 1 )); then
      echo "Retornou mais de um nome de usuário."
      echo " "
      echo "Nome: $nome $sobrenome" >> /var/log/usuarios/erro.log
      echo "Matrícula: $matricula" >>  /var/log/usuarios/erro.log
      echo "Erro: Retornou mais de um nome de usuário." >> /var/log/usuarios/erro.log
      echo "" >> /var/log/usuarios/erro.log

    else

      echo "Criando usuario $ldap para o aluno $nome $sobrenome do curso $curso."
      useradd -m -d /home/alunos/$ldap -s /bin/bash  -c "$nome $sobrenome,$curso,$matricula" $ldap

      echo "Usando a matricula $matricula como senha temporária do usuario $ldap."
      echo "$ldap:$matricula" |chpasswd
  
      echo "Obrigando usuário $ldap a mudar senha no proximo login."
      chage -d 0 $ldap

      echo "Adicionando usuário $ldap ao grupo alunos."
      addgroup $ldap alunos
  
      echo "Mudando a permissão da pasta /home/alunos/$ldap."
      chmod -R 700 /home/alunos/$ldap

      echo "Mudando grupo dono da pasta /home/alunos/$ldap."
      chown -R $ldap:alunos /home/alunos/$ldap

      echo "Dando permissão de leitura aos usuários do grupo professores."
      setfacl -m g:professores:r /home/alunos/$ldap
 
      echo "Conta $ldap do usuário $nome $sobrenome criada"
      echo " "
      echo "Nome: $nome $sobrenome" >> /var/log/usuarios/novos.log
      echo "Matrícula: $matricula" >> /var/log/usuarios/novos.log
      echo "Nome de usuário: $ldap" >> /var/log/usuarios/novos.log
      echo "" >> /var/log/usuarios/novos.log    
    fi

  ##################### Usuários com matrículas trancadas #####################

  elif [ "$estado" = "T" ]; then
    echo "Usuário $nome $sobrenome marcado como trancado."
    if [ "$nomelocal" = "$nome $sobrenome" ]; then

      echo "Usuário encontrado."
      echo "Desabilitando o login do usuário."
      echo ""
      echo "Nome: $nome $sobrenome" >> /var/log/usuarios/trancados.log
      echo "Matrícula: $matricula" >> /var/log/usuarios/trancados.log
      echo "Nome de usuário: $usuariolocal" >> /var/log/usuarios/trancados.log
      echo "Situação: o usuário teve seu login desabilitado." >> /var/log/usuarios/trancados.log
      echo "" >> /var/log/usuarios/trancados.log

    else

      echo "O usuário $nome $sobrenome foi marcado como trancado mas não foi encontrado registrado no sistema."
      echo ""
      echo "Nome: $nome $sobrenome" >> /var/log/usuarios/trancados.log
      echo "Matrícula: $matricula" >> /var/log/usuarios/trancados.log
      echo "Situação: o usuário não teve seu login desabilitado porque não estava registrado no sistema." >> /var/log/usuarios/trancados.log
      echo "" >> /var/log/usuarios/trancados.log      

    fi

  ##################### Usuários aprovados #####################

  elif [ "$estado" = "A" ]; then
    echo "Usuário $nome $sobrenome marcado como aprovado."
    if [ "$nomelocal" = "$nome $sobrenome" ]; then
      pasta=$(ls /home/alunos/$usuariolocal)
      if [ -z "${pasta}" ]; then
        echo "Usuário $usuariolocal, marcado como aprovado, foi excluído bem como sua pasta pois a esta estava vazia."
        echo ""
        echo "Nome: $nome $sobrenome" >> /var/log/usuarios/aprovados.log
        echo "Matrícula: $matricula" >>  /var/log/usuarios/aprovados.log
        echo "Nome de usuário: $usuariolocal" >> /var/log/usuarios/aprovados.log
        echo "Situação: o usuário bem como sua pasta foram excluídos." >> /var/log/usuarios/aprovados.log
        echo "" >> /var/log/usuarios/aprovados.log
        userdel -r $usuariolocal

      else

        echo "O usuário $usuariolocal está com o estado de aprovado, no entanto sua pasta de usuário não estava vazia, por isso não foi excluída."
        echo ""
        echo "Nome: $nome $sobrenome" >> /var/log/usuarios/aprovados.log
        echo "Matrícula: $matricula" >>  /var/log/usuarios/aprovados.log
        echo "Nome de usuário: $usuariolocal" >> /var/log/usuarios/aprovados.log
        echo "Situação: o usuário não foi excluído porque sua pasta não estava vazia." >> /var/log/usuarios/aprovados.log
        echo "" >> /var/log/usuarios/aprovados.log

      fi

    else

      echo "O usuário $nome $sobrenome não estava cadastrado."
      echo ""
      echo "Nome: $nome $sobrenome" >> /var/log/usuarios/aprovados.log
      echo "Matrícula: $matricula" >>  /var/log/usuarios/aprovados.log
      echo "Situação: o usuário não foi excluído porque não estava cadastrado." >> /var/log/usuarios/aprovados.log
      echo "" >> /var/log/usuarios/aprovados.log

    fi
  fi
done < $1

O script acima gera seis tipos de log:

  • /var/log/usuarios/aprovados.log → contém os usuário que tem seu estado como aprovados (A):
  • /var/log/usuarios/cancelados.log → contém os usuário que tem seu estado como cancelado (C);
  • /var/log/usuarios/trancados.log → contém os usuário que tem seu estado como trancado (T);
  • /var/log/usuarios/erro.log → contém os usuários que não retornaram nome de usuário no LDAP ou retonaram múltiplos nomes de usuário;
  • /var/log/usuarios/existentes.log → contém os usuários da lista informada que já estão cadastrados (M);
  • /var/log/usuarios/novos.log → contém os nomes de usuários criados na última vez o script foi executado (M).

A cada execução, todos os logs na pasta "/var/log/usuarios" são apagados.
Há também um script para a criação manual de usuários de alunos, caso seja encontrado mais de um nome de usuário para o mesmo aluno ou caso não seja encontrado nenhum nome de usuário.
A sintaxe de utilização é:

root@quartus-matlab:/# ./criar-usuario-aluno "nome_de_usuario" "NOME COMPLETO" "matrícula" "curso"
root@quartus-matlab:/# ./criar-usuario-aluno "maria.fs" "MARIA FONSECA DE SOUZA" "246801357-9" "Engenharia de Telecomunicações"

O código do script é:

#!/bin/bash

nomedeusuario=$1
nomecompleto=$2
matricula=$3
curso=$4

  echo "Criando usuario $nomedeusuario para o aluno $nomecompleto"
  useradd -m -d /home/alunos/$nomedeusuario -s /bin/bash  -c "$nomecompleto,$curso,$matricula" $nomedeusuario

  echo "Usando a matricula $matricula como senha do usuario $nomedeusuario."
  echo "$nomedeusuario:$matricula" |chpasswd
  
  echo "Obrigando usuario a mudar senha no proximo login."
  chage -d 0 $nomedeusuario

  echo "Adicionando usuario $nomedeusuario ao grupo alunos"
  addgroup $nomedeusuario alunos

  echo "Mudando grupo dono da pasta /home/alunos/$nomedeusuario."
  chown -R $nomedeusuario:alunos /home/alunos/$nomedeusuario
  
  echo "Mudando a permissao da pasta /home/alunos/$nomedeusuario"
  chmod -R 700 /home/alunos/$nomedeusuario
  
  echo "Conta $nomedeusuario do usuario $nomecompleto criada"
  echo " "

E há um script para a criação de usuários para os professores, usando a seguinte sintaxe:

root@quartus-matlab:/# ./criar-usuario-professor "usuario" "Nome Completo" "senhatemporaria"

#!/bin/bash

nomedeusuario=$1
nomecompleto=$2
senha=$3

  echo "Criando usuário $nomedeusuario para o professor $nomecompleto."
  useradd -m -d /home/professores/$nomedeusuario -s /bin/bash  -c "$nomecompleto" $nomedeusuario

  echo "Usando $senha como senha temporária do usuario $nomedeusuario."
  echo "$nomedeusuario:$senha" |chpasswd
  
  echo "Obrigando usuário a mudar senha no próximo login."
  chage -d 0 $nomedeusuario

  echo "Adicionando usuário $nomedeusuario ao grupo professores."
  addgroup $nomedeusuario professores
  
  echo "Mudando a permissão da pasta /home/professores/$nomedeusuario."
  chmod -R 700 /home/professores/$nomedeusuario
  
  echo "Conta $nomedeusuario do usuário $nomecompleto criada."
  echo " "

Uso do Gdrive

O Gdrive é uma ferramenta de gerência, em modo texto, de arquivos e diretórios no Google Drive. Abaixo, serão listados comandos úteis para o uso da ferramenta.


  • Uso

$ gdrive list → Lista os arquivos e pastas do diretório raiz. Na primeira vez que for executado, informará um link para que você acesse pelo navegador. Acessando o link, você receberá um código, copie e cole esse código no terminal ao lado de "Enter verification code:". Após isso você poderá usar a aplicação para manipular os arquivos da sua conta do Google Drive.

$ gdrive upload arquivo → envia um arquivo para o diretório raiz do Google Drive.
$ gdrive upload --parent ID_DA_PASTA arquivo → enviar um arquivo para uma pasta específica.
$ gdrive upload -r /caminho/da/pasta/no/pc → envia uma pasta com todo seu contéudo para o diretório raiz do sistema.
$ gdrive upload --parent ID_DA_PASTA -r /caminho/da/pasta/no/pc → envia uma pasta com todo seu conteúdo para uma pasta específica.
O ID da pasta pode ser obtido pela URL do Google Drive: https://drive.google.com/drive/u/0/folders/ID_DA_PASTA ;

$ gdrive download ID_DO_ARQUIVO → baixa um arquivo.

Programando Localmente a FPGA via JTAG com o Quartus II da Nuvem

Cenário de aplicação

Essa situação envolve em ter disponível uma placa com FPGA e USB-BLASTER conectada ao seu computador (local). Porém você deseja utilizar o Quartus 13 ou 16 da nuvem para a programação remota do FPGA.

Procedimento na maquina local

Conecte o kit com FPGA a sua maquina local e ligue esse kit. Verifique se os softwares minimos necessários para o reconhecimento da JTAG estão disponíveis na maquina local.

jtagconfig

Se tudo estiver correto, o monitor deverá apresentar uma tela indicando a porta USB e o tipo de FPGA que está conectado (se tiver mais de um todos serão listados). No exemplo abaixo um kit Mercurio IV (EP3C40/EP4CE(30|40)) está conectado a porta [3-3], e um kit DE2-115 (EP3C120/EP4CE115) está conectado a porta [5-2]

1) USB-Blaster [3-3]
 020F40DD   EP3C40/EP4CE(30|40)
2) USB-Blaster [5-2]
 020F70DD   EP3C120/EP4CE115

Em seguida executar os comandos abaixo na maquina local para habilitar o acesso remoto a JTAG através da porta USB.

/opt/altera/13.0sp1/nios2eds/nios2_command_shell.sh 
jtagd
jtagconfig --enableremote <senha_escolhida>


Procedimento na nuvem

Usando um terminal, verifique quais porta <60XXX> já estão em uso:

ssh  <seu_login>@191.36.8.33 netstat -lnt | grep 127.0.0.1:60[0-9][0-9][0-9]

Estabeleça um túnel ssh reverso fazendo um link entre um porta 60XXX não utilizada e a porta da jtag da maquina local, onde XXX é um numero livre.

ssh -XC -R <60XXX>:localhost:1309 <seu_login>@191.36.8.33

Execute o Quartus II versão 13.0sp

quartus -13 &

ou execute o Quartus II versão 16.0

quartus -16 &

No Quartus II é necessário abrir o programador [Tools > Programmer] em seguida [Edit > Hardware Setup] na aba [JTAG Settings] [Add Server] preencher os campos:

Server name: 127.0.0.1:60XXX
Server password: <senha_escolhida>

JTAG settings QUARTUS13.png

Em seguida é necessário selecionar a JTAG na aba [Hardware Settings]

Hardware settings QUARTUS13.png Agora o kit conectado a sua maquina local está pronto para ser programado remotamente a partir da nuvem.

Programação e visualização remota do kit FPGA

Provisoriamente estou experimentando disponibilizar um kit Mercúrio IV conectado a minha maquina. Segue o procedimento para acessar o kit através do quartus e visualizar o resultado.

Programação

Estabelecer um túnel ssh reverso fazendo um bind entre 60002 e a porta da jtag local

ssh -XC -R 60002:localhost:1309 <seu_usuário_na_nuvem>@191.36.8.33

No Quartus é necessário abrir o programador [Tools > Programmer] em seguida [Edit > Hardware Setup] na aba [JTAG Settings] [Add Server] preencher os campos:

Server name: 127.0.0.1:60002
Server password: lab_DLP_remoto2017

JTAG settings QUARTUS13.png

Em seguida é necessário selecionar a JTAG na aba [Hardware Settings]

Hardware settings QUARTUS13.png

Visualização

Para visualizar o resultado da programação do kit, está disponível uma câmera de vídeo que monitora on-line um kit. Para acessá-la de dentro da rede do IFSC, basta digitar a url da câmera:

 http://172.18.116.32/axis-cgi/mjpg/video.cgi

Remotamente de fora do IFSC, use o vlc na nuvem.

 vlc http://172.18.116.32/axis-cgi/mjpg/video.cgi

Eventualmente você pode não acesso aos kits, pois estão conectados a maquina do prof Moecke.

Hoje a porta de conexão é 60001, e a senha é senha.  --Marcos Moecke 14h12min de 30 de outubro de 2017 (-02)

Estão disponíveis 2 kits, mas o video só mostra um deles.

Dicas

Compartilhamento de arquivos via rede

Para compartilhar arquivos de maneira simplificada, é possível utilizar uma pequena aplicação em python chamada "SimpleHTTPServer":

python -m SimpleHTTPServer 8000

O comando acima, por exemplo, inicia um servidor web simples na porta 8000. Basta apenas, então, acessar em um navegador "http://ip_da_maquina:porta" e os arquivos da pasta o qual o comando foi executado aparecerão na página web. Isso permite que o usuário os baixe utilizando o comando "wget"

wget http://ip_da_maquina:porta/aquivo

No caso de download de um diretório, basta passar alguns argumentos para o "wget":

wget --recursive --no-parent http://ip_da_maquina:porta/pasta

Endereços IPs internos em uso no servidor

Esta seção desta página desinga-se a uso interno dos professores e administradores do servidor de aplicações.
A fim te ter-se uma melhor organização, recomendo a utilização a faixa de endereços 10.10.10.100 à 10.10.10.254 para a criação de contêineres, alocando, se possível, endereços em ordem crescente.
Para o redirecionamento de portas, consulte o item 1.2.5 (Redirecionamento de Portas).
Abaixo, estão listadas as pontes de rede presentes no Docker bem como os nomes dos contêineres associados às mesmas, sendo primeiramente referido o nome da ponte no sistema operacional de gerência e entre parênteses o nome que aparece no Docker (que é o mesmo que aparece no Portainer):

docker0 (bridge) → não é possível escolher o endereço IP nessa ponte

Endereço IP da interface: 172.17.0.1
Máscara de sub-rede:' 255.255.0.0 = 16
IP de início: 172.17.0.1
Último endereço IP: 172.17.0.254
Endereço de broadcast: 172.17.0.255
Gateway (automático): 172.17.0.1

DMZ191 (DMZ191) → não roteável devido ao virtualizador

Endereço IP da interface: 191.36.8.33
Máscara de sub-rede:' 255.255.255.224 = 27
IP de início: 191.36.8.33
Último endereço IP: 191.36.8.62
Endereço de broadcast: 191.36.8.63
Gateway (automático): 191.36.8.33

faixa10 (faixa10)

Endereço IP da interface: 10.10.10.10
Máscara de sub-rede: 255.255.255.0 = 24
IP de início: 10.10.10.1
Último endereço IP: 10.10.10.254
Endereço de broadcast: 10.10.10.255
Gateway (automático): 10.10.10.10

  • 10.10.10.1 → proxy-reverso
  • 10.10.10.2 → Portainer
  • 10.10.10.100 → quartus-matlab
  • 10.10.10.101 → hackrf
  • 10.10.10.102 → quartus-matlab2
  • 10.10.10.103 →
  • 10.10.10.104 → quartus-matlab3
  • 10.10.10.105 → grafana
  • 10.10.10.106 → influxdb
  • 10.10.10.107 → chronograf
  • 10.10.10.108 → PluvioStation
  • 10.10.10.109 →

Serviços Web em Execução