docker使用入门
参考资料
名词解释
- 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
- 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
- 主机: 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
- Docker Registry: Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用
- PGP: Pretty Good Privacy 是一套用于消息加密、验证的应用程序. PGP 本身是商业应用程序;对应的开源软件为 GPG(GnuPG)
- GPG: GNU Privacy Guard, 也是一种加密软件,它是 PGP 加密软件的开源替代程序. 在docker中主要用于容器的加密?
- volume: 卷
- Flask: 是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务
- bind mount: linux命令,将一个目录挂载到另一个
- CI / CD: Continuous Integrate, Continuous Deploy 持续集成和持续交付
- Dockerfile: 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
- Compose: 您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。 比Dockerfile集成度更高。或者说前者用来启动程序,后者用来生成镜像
- overlay: 相当于创建一个虚拟网络,将主机,多个容器,甚至多个docker daemon均覆盖进来,彼此之间均可以通信
- CNM: Container Network Model
- bridge: 早期的交换机雏形,交换机可以认为是多个bridge的集合。转发二层帧,起到信号放大的作用。网卡相当于是一个网桥/交换机,两者在一个网段内。arp和ping均可以通过
- automatic service discovery: 类似于DNS服务,使得 ping -c 2 alpine2 这样的操作可以实现
- kvm: Kernel-based Virtual Machine,是一种内建于linux中的开源虚拟化技术
- QEMU: 一种通用的开源计算机仿真器和虚拟器
安装
docker desktop
以下安装方法针对ubuntu
系统准备
在虚拟机上使用docker需要安装kvm
modprobe kvm
modprobe kvm_intel
lsmod | grep kvm
ls -al /dev/kvm
sudo usermod -aG kvm $USER # 添加用户态权限
安装新版qemu,文档要求5.2以上
wget https://download.qemu.org/qemu-7.1.0-rc3.tar.xz
tar xvJf qemu-7.1.0-rc3.tar.xz
cd qemu-7.1.0-rc3
./configure
make
sudo make install
configure需要安装ninja
sudo apt install re2c
git clone https://gitee.com/hclink_ai/ninja.git
cd ninja
python3 configure.py --bootstrap
sudo cp ./ninja /usr/bin
ninja --version
文件共享
grep "$USER" /etc/subuid >> /dev/null 2&>1 || (echo "$USER:100000:65536" | sudo tee -a /etc/subuid)
grep "$USER" /etc/subgid >> /dev/null 2&>1 || (echo "$USER:100000:65536" | sudo tee -a /etc/subgid)
echo $USER
cat /etc/subuid
cat /etc/subgid
sudo add-apt-repository ppa:jacob/virtualisation
sudo apt update
sudo apt -y install libvirt-clients libvirt-daemon bridge-utils
sudo apt install grub-common
grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) intel_iommu=on" # 开启IOMMU
sudo chmod a+rw /var/lib/docker
$ sudo service docker stop
$ sudo systemctl disable docker.service
$ sudo systemctl disable docker.socket
开始安装
安装前首先要清理原有的老文件
sudo apt remove docker-desktop
rm -r $HOME/.docker/desktop
sudo rm /usr/local/bin/com.docker.cli
sudo apt purge docker-desktop
如果没有gnome,需要先安装
sudo apt install gnome-terminal
开始安装Docker
sudo apt-get update
# 依赖
sudo apt-get install ca-certificates curl gnupg lsb-release
# GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 设置repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装engine
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 需要update之后才行,比较大,有500多M
# 也可以通过deb安装 Docker Desktop
sudo apt-get install ./docker-desktop-<version>-<arch>.deb
# 80多M
生成凭据,否则无法登录
gpg --generate-key
pass init 7865BA9185AFA2C26C5B505669FC4F36530097C2
注册
登录
验证
docker compose version
docker --version
docker version
加入用户组
docker ps # 正常会显示权限错误,此时需要加入组
sudo gpasswd -a $USER docker
newgrp docker
docker engine
可以使用脚本自动化安装
curl -sSL https://get.docker.com/ | sh
一般安装
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get install ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose
换源
阿里云的加速器:https://help.aliyun.com/document_detail/60750.html
网易加速器:http://hub-mirror.c.163.com
官方中国加速器:https://registry.docker-cn.com
ustc 的镜像:https://docker.mirrors.ustc.edu.cn
在 settings-> Docker Engine 中加入以下配置即可
"registry-mirrors": [
"http://hub-mirror.c.163.com"
]
如果是docker engine,换源方法如下
cd /etc/docker
vim daemon.json
# 添加源
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://ghcr.io",
"https://mirror.baidubce.com"
]
}
service docker restart
使用
常用方法
查看类
docker images # 查看镜像
docker ps # 查看容器
docker ps -a # 查看容器详细信息
docker --help # 查看帮助
docker -v # 查看版本
docker attach xx # 查看xx容器运行情况
运行类
docker run xx # 运行xx镜像
docker run xx && python3 hello.py -yy zz # 运行xx镜像并启动容器中的程序,后面可以加入命令行参数zz
docker run xx python3 hello.py # 同上
docker run -dit xx # 以互动方式后台运行镜像
docker start xx # 运行xx容器
docker stop xx
docker restart xx
管理类
systemctl start docker # 启动守护程序
systemctl stop docker
systemctl restart docker
docker system prune # 删除停止的容器,无用的网络,清缓存,删除无用的镜像
docker rm xx # 删除指定容器,支持简写前几位进行模糊匹配
docker rmi xx # 删除指定镜像
docker build -t xx . # 在当前文件夹选择Dockerfile进行镜像构建,镜像名为xx
sudo docker login -u xxx -p xxx # 上传前需要先登录
sudo docker tag storm moonfish/storm:v1.1 # 上传前要先重命名,格式为 账号/镜像名:版本号
sudo docker push moonfish/baikal:v1 # 上传
sudo docker pull moonfish/baikal:v1 # 下载
命令行参数
docker build
–network=host 相当于虚拟机中的host only选项,主机和容器共享网卡,名字也相同。
如果不输入参数,那么docker会自动构建一个桥接网络,容器会连接至虚拟网卡 docker0, 地址为127.17.0.1; 而容器会自动被赋予一个127网段的地址
docker run
- -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
- -d: 后台运行容器,并返回容器ID;
- -i: 以交互模式运行容器,通常与 -t 同时使用;
- -P: 随机端口映射,容器内部端口随机映射到主机的端口
- -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
- -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;提示符会变为#号
- –name=“nginx-lb”: 为容器指定一个名称;
- –dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
- -e username=“ritchie”: 设置环境变量
- –env-file=[]: 从指定文件读入环境变量;
- **-m 😗*设置容器使用内存最大值;
- –link=[]: 添加链接到另一个容器;
- –volume , -v: 绑定一个卷
docker exec
- -d: Detached Mode: 后台运行
- -e: 设置环境变量
- -i: 展示容器输入信息
STDIN - –privileged: 为命令提供一些扩展权限
- -t: 命令行交互模式
- -u: 设置用户名(format: <name|uid>[:<group|gid>])
- -w: 指定容器内的目录
docker network
docker的网络管理调用的是iptable
docker network create -d bridge my-bridge-network # 建立一个自定义的网络,指定为bridge模式;还可以为overlay模式
docker network create -d overlay my-multihost-network # overlay模式,多个容器之间可以放入同一个网段,有docker统一管理
sysctl net.ipv4.conf.all.forwarding=1 # 让自定义网络能够与外界通信
sudo iptables -P FORWARD ACCEPT # iptables 放通
other
docker create --name my-nginx --network my-net --publish 8080:80 nginx # 通过nginx镜像创建容器,指定名称,指定网络,指定端口映射
docker network connect my-net my-nginx # 连接正在运行的容器与指定网络
镜像制作
python
代码
python依赖
cd /path/to/python-docker
pip3 install Flask
pip3 freeze | grep Flask >> requirements.txt
requirements.txt
scapy==2.4.5
pika==1.3.0
nmap==0.0.1
Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.8-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
FROM ubuntu:20.04
WORKDIR /app
RUN ["mkdir", "-p", "/var/log/stormEngine"]
RUN ["apt", "update"]
RUN ["apt", "-y", "install", "ethtool", "tcpreplay", "iputils-ping"]
COPY . /app
FROM ubuntu:20.04
WORKDIR /app
COPY . /app
ENV TZ=Asia/Shanghai \
DEBIAN_FRONTEND=noninteractive
RUN mkdir -p /var/log/stormEngine \
&& apt update \
&& apt install -y tzdata net-tools ethtool tcpreplay iputils-ping\
&& ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \
&& echo ${TZ} > /etc/timezone \
&& dpkg-reconfigure --frontend noninteractive tzdata \
&& rm -rf /var/lib/apt/lists/*
build
docker build --tag hello .
docker build -t hello .
run
docker run hello
push
sudo docker tag storm moonfish/storm:v1.1
sudo docker login -u moonfish -p xxx
sudo docker push moonfish/storm:v1.1
java
jdk安装
sudo wget https://download.oracle.com/java/18/latest/jdk-18_linux-x64_bin.tar.gz
sudo vi /etc/profile
# 添加以下3行
export JAVA_HOME=/home/ubuntu/Programm/openjdk-18.0.2.1_linux-x64_bin/jdk-18.0.2.1
export CLASSPATH=.:$JAVA_HOME/lib
export PATH=.:$JAVA_HOME/bin:$JAVA_HOME/lib:$PATH
source /etc/profile
或者
sudo apt install openjdk-18-jre-headless # version 18~36ea-1
代码
将代码打包为jar包,需要在pom.xml文件中加入插件,以下代码可以同时生成胖包和瘦包
<build>
<plugins>
<plugin>
<!-- thin jar -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>main.MainApp</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<!-- add dependencies this jar -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- fat jar -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>main.MainApp</mainClass><!--这里改成自己的主类位置-->
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
FROM amazoncorretto:17.0.4-alpine3.15
WORKDIR /app
COPY . /app
ENV PATH=$PATH:$JAVA_HOME/bin
ENV JRE_HOME=${JAVA_HOME}/jre
ENV CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
FROM eclipse-temurin:11-jre-jammy
WORKDIR /app
COPY . /app
RUN ["mkdir", "-p", "/app/data"]
RUN ["mkdir", "-p", "/data/pcap_files"]
RUN ["cp", "/app/libpcap.so.1.9.1", "/usr/lib/x86_64-linux-gnu"]
加入libpcap.so.1.9.1
FROM eclipse-temurin:11-jre-jammy
WORKDIR /app
COPY . /app
ENV TZ=Asia/Shanghai \
DEBIAN_FRONTEND=noninteractive
RUN mkdir -p /app/data /data/pcap_files \
&& cp /app/libpcap.so.1.9.1 /usr/lib/x86_64-linux-gnu \
&& apt update \
&& apt install -y tzdata \
&& ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \
&& echo ${TZ} > /etc/timezone \
&& dpkg-reconfigure --frontend noninteractive tzdata \
&& rm -rf /var/lib/apt/lists/*
C
需要将所有依赖的库都拷贝到/app目录下,系统会自动优先链接,以下命令可以查看
lld baikal
代码
FROM ubuntu:16.04
WORKDIR /app
COPY . /app
ENV TZ=Asia/Shanghai \
DEBIAN_FRONTEND=noninteractive
RUN mkdir -p /usr/local/baikal /data/pcap_files \
&& apt update \
&& apt install -y tzdata \
&& ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \
&& echo ${TZ} > /etc/timezone \
&& dpkg-reconfigure --frontend noninteractive tzdata \
&& rm -rf /var/lib/apt/lists/*
多阶段构建
备注
-
A 2018 analysis found that a typical Docker use case involves running eight containers per host
-
需要开启nested virtualization,否则docker desktop无法使用
方法: 虚拟机设置->硬件->处理器->虚拟化 IntelVT-x/EPT
另外sudo apt -y install libvirt-clients libvirt-daemon qemu sudo add-apt-repository ppa:jacob/virtualisation -
image是镜像,位置在/var/lib/docker,里面有(没有镜像,)容器和分层,都存储在这里; 镜像位置是:setting->advanced->disk image location中可以查看和修改
-
and the volume’s contents exist outside the lifecycle of a given container.
-
C语言如果使用静态编译,那么就不需要向容器中拷贝依赖库了,镜像也会变得非常小。构建时只需要 From scratch即可
-
如果是C的helloworld 镜像必须添加CMD,否则无法运行。 因为镜像中没哟bash程序
-
“#” prompt 默认是root权限
-
若无特殊配置,不同host之间的容器无法通信; 除非使用overlay模式
-
File sharing 可以在IDE中修改源代码,在容器中测试
-
linux下docker desktop 会出现各种问题,最好用命令行操作
-
发布镜像时, 需要重命名为dockerhub用户名/镜像名,然后再push
-
desktop 和 docker engine的配置并不通用, bug太多,无法使用
-
时区修改
ENV TZ=Asia/Shanghai \ DEBIAN_FRONTEND=noninteractive RUN apt update \ && apt install -y tzdata \ && ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \ && echo ${TZ} > /etc/timezone \ && dpkg-reconfigure --frontend noninteractive tzdata \ && rm -rf /var/lib/apt/lists/*