Docker-如何用docker部署运行环境

如何避免sudo docker

  • 首先查看是否存在docker分组:

    sudo cat /etc/group | grep docker
    
  • 如果没有docker分组, 就创建:

    sudo groupadd -g 999 docker
    
  • 将当前用户添加到docker分组:

    sudo usermod -aG docker $USER
    
  • 修改docker daemon绑定的unix套接字的权限, 保证docker分组的用户能够访问:

    sudo chmod a+rw /var/run/docker.sock
    
  • 将当前用户退出后, 重新登录.

  • 重启docker daemon:

    sudo systemctl restart docker
    

结束.

使用Dockerfile初步构建镜像

使用以下Dockerfile可以对基础镜像进行下载依赖等操作.

FROM ubuntu:latest
ENV DEBIAN_FRONTEND noninteractive
RUN apt update && apt install -y ca-certificates build-essential sudo neovim htop neofetch git curl wget net-tools openssh-server nginx inetutils-ping fzf tmux ranger
RUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
  • 基础镜像和电脑的架构相关, 注意, 例如ARM架构的ubuntu镜像就是arm64v8/ubuntu.

然后使用如下命令构建镜像:

docker build -t 容器名:tag .

进行一步构建镜像

配置免密登录

  • 首先用passwd设置一下root账户的密码.

  • 启动ssh服务:

    service ssh start
    
  • 然后在本地的~/.ssh/config中添加配置:

    Host 别名
        HostName 服务器IP
        User root
        Port 20000
    
  • 然后使用ssh-copy-id 别名就可以配置成功.

配置软件源

进入容器后, 配置软件源, 软件源仓库是: https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/

注意软件源和架构与OS的发行版有关, 发行版可以通过`cat /etc/issue`查看.

配置代理

  • 如果docker容器要在本地, 可以直接在Docker容器内使用host.docker.internal.

  • 如果docker容器在远程,

    • 那么首先需要在本地建立隧道, 注意这个IP一定要是0.0.0.0.
    ssh -NR 0.0.0.0:<docker代理端口>:127.0.0.1:[本地代理端口] <docker的别名>
    
    • 然后在Docker容器内使用all_proxy, 命令是export all_proxy="socks5h://127.0.0.1:docker代理端口"

注意, 如果出现了Port Forwarding Failed, 那么需要在服务器端用如下命令找到占用端口的ssh进程:

sudo netstat -anp | grep 服务端代理端口号

然后用sudo kill 服务端代理端口号杀掉进程.

配置Git

使用以下两行命令就可以完成Git的配置:

git config --global user.name "你设置的用户名"
git config --global user.email "你的邮箱"

之后, 在github上需要配置Docker容器的SSH-key, 直接将cat ~/.ssh/id_rsa.pub这个公钥放到Github上即可.

将镜像变为容器

Docker的网络通信

容器向主机通信

在容器中, 宿主机的主机名可以表示为: host.docker.internal.

容器之间通信

容器之间通信可以采用自定义的桥接网络.

  • 首先创建桥接网络:

    docker network create 自定义网络名称
    
  • 将正在运行的容器连接到自定义网络:

    docker network connect 自定义网络 容器名
    
  • 创建容器时, 可以使用--net选项指定网络.

容器之间访问时, 主机名就是容器名, docker会有专门的DNS去解析.

如何测试容器与容器之间通信

可以采用docker调试用镜像busybox, 使用busybox用一行命令即可:

docker run -it --rm --net 自定义网络名称 busybox

然后在busybox容器内使用ping命令.

主机向容器通信

可以通过端口转发.

Docker的存储

绑定挂载

绑定挂载适合宿主机和docker镜像需要进行文件同步的场景.

在容器运行时, 只需要加上-v 本地某个目录的绝对路径:容器中这个路径的绝对路径即可.

Volume卷

Volume卷适合需要将数据在不同Docker容器进行迁移/备份的场景.

  • Volume中的数据只能在Docker容器中进行修改, 不能在宿主机上修改.

使用方法如下:

  • 第一步: 创建一个Volume:

    docker volume create 卷名字
    
  • 第二步: 将卷挂载到Docker容器上, 在容器启动时加上这个选项:

    -v 卷名字:容器中的一个目录的绝对路径
    
    • 之后, 只要在Docker容器中往这个目录里放了数据, 就相当于在卷中放了数据.

删除容器之后, 卷还会被保留, 可以被挂载到其他容器中.

docker-compose

docker-compose可以用一个yaml文件配置docker容器的启动, 配置的模板如下:

文件名字叫compose.yaml.

注意, 映射的端口一般考虑以下三种情况:

  • 20000:22: 用于ssh登陆.
  • 9998:9998: 用于代理.
  • 20001:80: 用于测试网络.
services:

  容器名字:
    image: 基于哪个镜像构建
    container_name: 容器名字
    tty: true
    extra_hosts:
      - "host.docker.internal:host-gateway"
    ports:
      - 本地端口1:容器端口1
      - 本地端口2:容器端口2
      - ...
    environment:
      环境变量1: 值1
      环境变量2: 值2
      ...
    networks:
      - 连接到的网络1
      - 连接到的网络2
      - mynet
    volumes:
      - 卷的名字:挂载到容器哪个目录 # 这个是卷挂载(volume)
      - 宿主机目录:容器目录 # 这个是绑定挂载(bind mount)
      - wordpress:/var/www/html
# 这是个例子
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql
# 这里会自动创建卷
volumes:
  - wordpress:
  - db:
# 这里会自动创建网络
networks:
  - mynet

然后直接运行docker compose up -d即可在后台启动Docker容器.

如果要进入Docker容器, 用这个命令:

docker exec -it 容器名 /bin/bash

LazyDocker

可以使用类似LazyGit的Docker客户端 LazyDocker管理Docker镜像, 容器, 网络, 卷等.

本地编辑, 远端执行

配置好远程的运行环境后, 在本地编辑后, 需要在远端执行代码, 这里就要解决两个问题:

  • 如何将本地代码和远端代码同步?
  • 如何在本地用一行命令在远端执行代码?

本地和远端代码同步

  • 如果是远程的服务器上的Docker镜像, 可以使用rsync.nvim插件, 使用rsync命令进行同步.
  • 如果是本地的Docker镜像, 可以采用绑定挂载.

远端执行代码

可以用ssh在本地用一行命令远程执行代码:

ssh user@host '
    命令1 && \
    命令2 && \
    命令3 && \
    ...
'