超值一篇分享,Docker:从入门到实战过程全记录

7b58fdbfb107ce8604702deec2a06265.gif

作者 | 天元浪子

来源 | CSDN博客

987ddf475ec73962a11a4c021c82f258.png

和Docker相关的概念

想要真正理解Docker,就不得不从虚拟化技术的发展历程说起。普遍认为虚拟化技术经历了物理机时代、虚拟机时代,目前已经进入到了容器化时代。可以说,Docker是虚拟化技术不断发展的必然结果。

那么,什么是容器呢?容器和虚拟机有什么不同?Docker和容器又是什么关系呢?搞明白这几个问题,Docker的概念就清晰了。

1.1 虚拟机和容器

借助于VMWare等软件,可以在一台计算机上创建多个虚拟机,每个虚拟机都拥有独立的操作系统,可以各自独立的运行程序。这种分身术虽然隔离度高(操作系统级),使用方便(类似物理机),但占用存储资源多(GB级)、启动速度慢(分钟级)的缺点也是显而易见的。

相较于虚拟机,容器(Container)是一种轻量型的虚拟化技术,它虚拟的是最简运行环境(类似于沙盒)而非操作系统,启动速度快(秒级)、占用存储资源少(KB级或MB级),容器间隔离度为进程级。在一台计算机上可以运行上千个容器,这是容器技术对虚拟机的碾压式优势。

1.2 容器、镜像和Docker

Docker是一个开源的应用容器引擎,可以创建容器以及基于容器运行的程序。Docker可以让开发者打包他们的应用和依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。

听起来很简单,但是在Docker和容器之间,还隐藏着一个镜像的概念,令初学者颇感困惑。本质上,Docker镜像是一个特殊的文件系统,它提供容器运行时所需的程序、库、资源、配置等文件。Docker镜像类似于一个py文件,它需要Docker的运行时(类似于Python解释器)运行。镜像被运行时,即创建了一个镜像的实例,一个实例就是一个容器。

1.3 Docker 和 k8s

作为容器引擎,Docker为容器化的应用程序提供了开放的标准,使得开发者可以用管理应用程序的方式来管理基础架构,实现快速交付、测试和部署代码。随着容器的大量使用,又产生了如何协调、调度和管理容器的问题,Docker的容器编排应运而生。

k8s是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理,是一个开源的,用于管理云平台中多个主机上的容器化的应用,k8s的目标是让部署容器化的应用简单并且高效,k8s提供了应用部署、规划、更新、维护的一种机制。

Docker和k8sr都是以containerd(容器化标准)作为运行时,因此使用Docker创建的镜像完全可以在k8s中无障碍的使用。

82ac520abbcbc5086ab2100f2fafc8e5.png

Docker的安装

2.1 在ubuntu中安装

在linux系统中安装Docker非常简单,官方为我们提供了一键安装脚本。这个方法也适用于Debian或CentOS等发行版。

curl -sSL https://get.daocloud.io/docker | sh

安装过程如果出现超时,不要灰心,多试几次,总会成功的。安装完成后,Docker只能被root用户使用,可以使用下面的命令取消权限限制:

sudo gpasswd -a <你的用户名> docker

然后,重启docker服务:

sudo service docker restart

最后,关闭当前的命令行,重新打开新的命令行就可以了。

顺便提一下,如果在CentOS下安装,可能会出现一堆类似于下面的错误:

问题 1: problem with installed package podman-2.0.5-5.module_el8.3.0+512+b3b58dca.x86_64- package podman-2.0.5-5.module_el8.3.0+512+b3b58dca.x86_64 requires runc >= 1.0.0-57, but none of the providers can be installed- package podman-3.0.1-6.module_el8.4.0+781+acf4c33b.x86_64 requires runc >= 1.0.0-57, but none of the providers can be installed- package podman-3.0.1-7.module_el8.4.0+830+8027e1c4.x86_64 requires runc >= 1.0.0-57, but none of the providers can be installed- package containerd.io-1.4.6-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- cannot install the best candidate for the job- package runc-1.0.0-64.rc10.module_el8.4.0+522+66908d0c.x86_64 is filtered out by modular filtering- package runc-1.0.0-65.rc10.module_el8.4.0+819+4afbd1d6.x86_64 is filtered out by modular filtering- package runc-1.0.0-70.rc92.module_el8.4.0+786+4668b267.x86_64 is filtered out by modular filtering- package runc-1.0.0-71.rc92.module_el8.4.0+833+9763146c.x86_64 is filtered out by modular filtering问题 2: package podman-3.0.1-6.module_el8.4.0+781+acf4c33b.x86_64 requires runc >= 1.0.0-57, but none of the providers can be installed- package containerd.io-1.4.3-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.3-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.3-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package containerd.io-1.4.3-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package docker-ce-3:20.10.7-3.el8.x86_64 requires containerd.io >= 1.4.1, but none of the providers can be installed- package containerd.io-1.4.3-3.2.el8.x86_64 conflicts with runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.3-3.2.el8.x86_64 obsoletes runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.3-3.2.el8.x86_64 conflicts with runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package containerd.io-1.4.3-3.2.el8.x86_64 obsoletes runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package podman-catatonit-3.0.1-6.module_el8.4.0+781+acf4c33b.x86_64 requires podman = 3.0.1-6.module_el8.4.0+781+acf4c33b, but none of the providers can be installed- problem with installed package podman-catatonit-2.0.5-5.module_el8.3.0+512+b3b58dca.x86_64- package podman-catatonit-3.0.1-7.module_el8.4.0+830+8027e1c4.x86_64 requires podman = 3.0.1-7.module_el8.4.0+830+8027e1c4, but none of the providers can be installed- package podman-3.0.1-7.module_el8.4.0+830+8027e1c4.x86_64 requires runc >= 1.0.0-57, but none of the providers can be installed- package containerd.io-1.4.3-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.3-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.3-3.2.el8.x86_64 conflicts with runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.3-3.2.el8.x86_64 obsoletes runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.4-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.4-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-68.rc92.module_el8.3.0+475+c50ce30b.x86_64- cannot install the best candidate for the job- package runc-1.0.0-64.rc10.module_el8.4.0+522+66908d0c.x86_64 is filtered out by modular filtering- package runc-1.0.0-65.rc10.module_el8.4.0+819+4afbd1d6.x86_64 is filtered out by modular filtering- package runc-1.0.0-70.rc92.module_el8.4.0+786+4668b267.x86_64 is filtered out by modular filtering- package runc-1.0.0-71.rc92.module_el8.4.0+833+9763146c.x86_64 is filtered out by modular filtering- package containerd.io-1.4.4-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.4-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.4-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package containerd.io-1.4.4-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-70.rc92.module_el8.4.0+673+eabfc99d.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 conflicts with runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package containerd.io-1.4.6-3.1.el8.x86_64 obsoletes runc provided by runc-1.0.0-73.rc93.module_el8.4.0+830+8027e1c4.x86_64- package podman-catatonit-2.0.5-5.module_el8.3.0+512+b3b58dca.x86_64 requires podman = 2.0.5-5.module_el8.3.0+512+b3b58dca, but none of the providers can be installed- package podman-2.0.5-5.module_el8.3.0+512+b3b58dca.x86_64 requires runc >= 1.0.0-57, but none of the providers can be installed

这是由于docker和Podman冲突造成的,需要先卸载Podman:

yum erase podman buildah

2.2 在Win10中安装

Docker的运行,依赖linux的环境,官方提供了Docker Desktop for Windows,但是它需要安装Hyper-V,Hyper-V是微软开发的虚拟机,类似于 VMWare 或 VirtualBox,仅适用于 Windows 10。这个虚拟机一旦启用,QEMU、VirtualBox 或 VMWare Workstation 15 及以下版本将无法使用!如果你必须在电脑上使用其他虚拟机(例如开发 Android 应用必须使用的模拟器),请不要使用 Hyper-V!

我的电脑是win10家庭版,不能直接安装hyper-v,需要将下面的命令保存到cmd文件中:

pushd "%~dp0"dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txtfor /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"del hyper-v.txtDism /online /enable-feature /featurename:Microsoft-Hyper-V-All /LimitAccess /ALL

然后在cmd文件上点击右键,选择使用管理员运行。执行完毕后会重启,在重启的过程中进行安装。

2.3 Hello world

docker服务启动的情况下,运行下面的命令:

docker run ubuntu:20.04 /bin/echo "Hello world"

此命令的含义是:

  • docker run:运行docker镜像命令

  • ubuntu:20.04:镜像名称为ubuntu版本号为20.04

  • /bin/echo “Hello world”:运行参数,此镜像的参数含义为运行镜像的echo命令显示hello world

第一次运行时,因为本地没有ubuntu:20.04镜像,docker会自动从镜像服务器下载。下载过程可能需要多试几次,只要成功一次,以后执行就不再需要下载了。

docker官方还提供了一个hello-world镜像,可以直接运行:

docker run hello-world

此命令省略了镜像版本和运行参数,docker使用latest作为版本,即最新版本。

从hello world的例子中,也可以体验到,docker实例的运行是非常快的。

17ec549210ebd682480e333ae9eb50c4.png

Docker镜像的使用

docker官方的镜像库比较慢,在进行镜像操作之前,需要将镜像源设置为国内的站点。

新建文件/etc/docker/daemon.json,输入如下内容:

{"registry-mirrors" : ["https://registry.docker-cn.com","https://docker.mirrors.ustc.edu.cn","http://hub-mirror.c.163.com","https://cr.console.aliyun.com/"]
}

然后重启docker的服务:

systemctl restart docker

3.1 列出本地所有镜像

执行命令 docker images 可以查看

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              20.04               f643c72bc252        5 weeks ago         72.9MB
hello-world         latest              bf756fb1ae65        12 months ago       13.3kB

当前我本地只有刚才安装的两个镜像。

3.2 从镜像库中查找镜像

执行命令 docker search 镜像名称可以从docker镜像库中查找镜像。

$ docker search python
NAME                             DESCRIPTION                                     STARS              OFFICIAL          AUTOMATED
python                           Python is an interpreted, interactive, objec…   5757                [OK]                
django                           Django is a free web application framework, …   1039                [OK]                
pypy                             PyPy is a fast, compliant alternative implem…   260                 [OK]                
joyzoursky/python-chromedriver   Python with Chromedriver, for running automa…   57                                      [OK]
nikolaik/python-nodejs           Python with Node.js                             57                                      [OK]
arm32v7/python                   Python is an interpreted, interactive, objec…   53                                      
circleci/python                  Python is an interpreted, interactive, objec…   42                                      
centos/python-35-centos7         Platform for building and running Python 3.5…   38                                      
centos/python-36-centos7         Platform for building and running Python 3.6…   30                                      
hylang                           Hy is a Lisp dialect that translates express…   29                  [OK]                
arm64v8/python                   Python is an interpreted, interactive, objec…   24                                      
revolutionsystems/python         Optimized Python Images                         18                                      
centos/python-27-centos7         Platform for building and running Python 2.7…   17                                      
bitnami/python                   Bitnami Python Docker Image                     10                                      [OK]
publicisworldwide/python-conda   Basic Python environments with Conda.           6                                       [OK]
d3fk/python_in_bottle            Simple python:alpine completed by Bottle+Req…   5                                       [OK]
dockershelf/python               Repository for docker images of Python. Test…   5                                       [OK]
clearlinux/python                Python programming interpreted language with…   4                                       
i386/python                      Python is an interpreted, interactive, objec…   3                                       
ppc64le/python                   Python is an interpreted, interactive, objec…   2                                       
centos/python-34-centos7         Platform for building and running Python 3.4…   2                                       
amd64/python                     Python is an interpreted, interactive, objec…   1                                       
ccitest/python                   CircleCI test images for Python                 0                                       [OK]
s390x/python                     Python is an interpreted, interactive, objec…   0                                       
saagie/python                    Repo for python jobs                            0

最好选择官方(OFFICIAL)的镜像,这样的镜像最稳定一些。

3.3 下载新的镜像

执行命令docker pull 镜像名称:版本号即可下载新的镜像。

$ docker pull python:3.8
3.8: Pulling from library/python
6c33745f49b4: Pull complete 
ef072fc32a84: Pull complete 
c0afb8e68e0b: Pull complete 
d599c07d28e6: Pull complete 
f2ecc74db11a: Pull complete 
26856d31ce86: Pull complete 
2cd68d824f12: Pull complete 
7ea1535f18c3: Pull complete 
2bef93d9a76e: Pull complete 
Digest: sha256:9079aa8582543494225d2b3a28fce526d9a6b06eb06ce2bac3eeee592fcfc49e
Status: Downloaded newer image for python:3.8
docker.io/library/python:3.8

镜像下载后,就可以使用镜像来创建容器了。

cd2cec5ded40b9aea81240615223c47b.png

Docker容器的使用

4.1 启动容器

执行命令docker run即可启动容器,也就是创建某个镜像的实例。docker run命令非常复杂,可以先执行一个docker run --help来查看帮助:

$ docker run --helpUsage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]Run a command in a new containerOptions:--add-host list                  Add a custom host-to-IP mapping (host:ip)-a, --attach list                    Attach to STDIN, STDOUT or STDERR--blkio-weight uint16            Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)--blkio-weight-device list       Block IO weight (relative device weight) (default [])--cap-add list                   Add Linux capabilities--cap-drop list                  Drop Linux capabilities--cgroup-parent string           Optional parent cgroup for the container--cidfile string                 Write the container ID to the file--cpu-period int                 Limit CPU CFS (Completely Fair Scheduler) period--cpu-quota int                  Limit CPU CFS (Completely Fair Scheduler) quota--cpu-rt-period int              Limit CPU real-time period in microseconds--cpu-rt-runtime int             Limit CPU real-time runtime in microseconds-c, --cpu-shares int                 CPU shares (relative weight)--cpus decimal                   Number of CPUs--cpuset-cpus string             CPUs in which to allow execution (0-3, 0,1)--cpuset-mems string             MEMs in which to allow execution (0-3, 0,1)-d, --detach                         Run container in background and print container ID--detach-keys string             Override the key sequence for detaching a container--device list                    Add a host device to the container--device-cgroup-rule list        Add a rule to the cgroup allowed devices list--device-read-bps list           Limit read rate (bytes per second) from a device (default [])--device-read-iops list          Limit read rate (IO per second) from a device (default [])--device-write-bps list          Limit write rate (bytes per second) to a device (default [])--device-write-iops list         Limit write rate (IO per second) to a device (default [])--disable-content-trust          Skip image verification (default true)--dns list                       Set custom DNS servers--dns-option list                Set DNS options--dns-search list                Set custom DNS search domains--domainname string              Container NIS domain name--entrypoint string              Overwrite the default ENTRYPOINT of the image-e, --env list                       Set environment variables--env-file list                  Read in a file of environment variables--expose list                    Expose a port or a range of ports--gpus gpu-request               GPU devices to add to the container ('all' to pass all GPUs)--group-add list                 Add additional groups to join--health-cmd string              Command to run to check health--health-interval duration       Time between running the check (ms|s|m|h) (default 0s)--health-retries int             Consecutive failures needed to report unhealthy--health-start-period duration   Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s)--health-timeout duration        Maximum time to allow one check to run (ms|s|m|h) (default 0s)--help                           Print usage-h, --hostname string                Container host name--init                           Run an init inside the container that forwards signals and reaps processes-i, --interactive                    Keep STDIN open even if not attached--ip string                      IPv4 address (e.g., 172.30.100.104)--ip6 string                     IPv6 address (e.g., 2001:db8::33)--ipc string                     IPC mode to use--isolation string               Container isolation technology--kernel-memory bytes            Kernel memory limit-l, --label list                     Set meta data on a container--label-file list                Read in a line delimited file of labels--link list                      Add link to another container--link-local-ip list             Container IPv4/IPv6 link-local addresses--log-driver string              Logging driver for the container--log-opt list                   Log driver options--mac-address string             Container MAC address (e.g., 92:d0:c6:0a:29:33)-m, --memory bytes                   Memory limit--memory-reservation bytes       Memory soft limit--memory-swap bytes              Swap limit equal to memory plus swap: '-1' to enable unlimited swap--memory-swappiness int          Tune container memory swappiness (0 to 100) (default -1)--mount mount                    Attach a filesystem mount to the container--name string                    Assign a name to the container--network network                Connect a container to a network--network-alias list             Add network-scoped alias for the container--no-healthcheck                 Disable any container-specified HEALTHCHECK--oom-kill-disable               Disable OOM Killer--oom-score-adj int              Tune host's OOM preferences (-1000 to 1000)--pid string                     PID namespace to use--pids-limit int                 Tune container pids limit (set -1 for unlimited)--platform string                Set platform if server is multi-platform capable--privileged                     Give extended privileges to this container-p, --publish list                   Publish a container's port(s) to the host-P, --publish-all                    Publish all exposed ports to random ports--read-only                      Mount the container's root filesystem as read only--restart string                 Restart policy to apply when a container exits (default "no")--rm                             Automatically remove the container when it exits--runtime string                 Runtime to use for this container--security-opt list              Security Options--shm-size bytes                 Size of /dev/shm--sig-proxy                      Proxy received signals to the process (default true)--stop-signal string             Signal to stop a container (default "SIGTERM")--stop-timeout int               Timeout (in seconds) to stop a container--storage-opt list               Storage driver options for the container--sysctl map                     Sysctl options (default map[])--tmpfs list                     Mount a tmpfs directory-t, --tty                            Allocate a pseudo-TTY--ulimit ulimit                  Ulimit options (default [])-u, --user string                    Username or UID (format: <name|uid>[:<group|gid>])--userns string                  User namespace to use--uts string                     UTS namespace to use-v, --volume list                    Bind mount a volume--volume-driver string           Optional volume driver for the container--volumes-from list              Mount volumes from the specified container(s)-w, --workdir string                 Working directory inside the container

比如我们要执行python的shell,需要添加-it参数,即:docker run -it python:3.8

$ docker run -it python:3.8 
Python 3.8.7 (default, Dec 22 2020, 18:46:25) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

4.2 将宿主机的文件挂载到容器

docker容器与宿主机是隔离的,要想让容器内的程序能访问宿主机上的文件,需要通过-v参数将宿主机的文件挂载到容器中。

比如我们在宿主机上有一个hello.py,可以打印hello,想要在python容器中执行,就需要进行挂载。-v后还需要接两个参数,分别是宿主机的目录和容器内的目录,两者使用:分隔,路径必须都是绝对路径。

我的hello.py保存在主目录的/docker_test目录中,将这个目录挂载到容器的/docker_test目录,然后在容器内执行python /docker_test/hello.py:

$ docker run -v ~/docker_test:/docker_test python:3.8 python /docker_test/hello.py
hello

4.3 容器的端口映射

我们修改一下hello.py,创建一个socket服务端,并监听5000端口,当有客户端连接时,打印客户端的地址,先客户端发送hello,然后关闭连接:

import socketip_port = ('127.0.0.1', 5000)sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)while True:print('server waiting...')conn,addr = sk.accept()print(addr)conn.sendall(b'hello\n')conn.close()

在容器内执行:

docker run -v ~/docker_test:/docker_test python:3.8 python /docker_test/hello.py

接下来,尝试用telnet命令连接,结果却是失败的。原因是,127.0.0.1是宿主机的ip地址,5000是容器的端口,这与我们的习惯稍微有些不同。事实上,docker的容器是非常轻量的,它并没有自己的网络,要想访问容器的端口,需要进行端口映射,将容器的某端口映射到宿主机的端口,客户端连接时,只要与宿主机的端口进行连接就可以了。

需要注意的是,上面的代码创建的服务器,无论如何也不可能被客户端连接,因为代码中绑定了127.0.0.1的ip,在容器中运行时,需要绑定所有ip,即0.0.0.0。

import socketip_port = ('0.0.0.0', 5000)sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)while True:print('server waiting...')conn,addr = sk.accept()print(addr)conn.sendall(b'hello\n')conn.close()

然后,再使用-p参数,-p还需要三个参数,即宿主机的ip地址、宿主机的端口、容器的端口,三者之间使用:分隔。一般的,可以将宿主机的ip地址省略,只写宿主机的端口:容器的端口即可。

docker run -v ~/docker_test:/docker_test -it -p 5001:5000 python:3.8 python /docker_test/hello.py

这样,就将容器的5000端口映射到了宿主机的5001端口,使用:

telnet 127.0.0.1 5001

即可与容器中的服务器进行连接。

4.4 容器管理

上面的服务运行之后,可以使用docker ps命令,查看运行中的容器:

$ docker ps
CONTAINER ID     IMAGE           COMMAND                  CREATED           STATUS         PORTS                    NAMES
ec4c86b8a163     python:3.8      "python /docker_test…"   5 seconds ago     Up 4 seconds   0.0.0.0:5000->5000/tcp   eager_wilson

显示的内容有下面几列:

  • CONTAINER ID:容器ID

  • IMAGE:镜像名称和版本

  • COMMAND:执行的命令

  • CREATED:容器创建时间

  • STATUS:容器的状态

  • PORTS:端口映射

  • NAMES:容器名

要想结束容器,可以使用docker kill 容器ID命令。

e0f587cd02a2a56712fc2eae70ac700e.png

自制Docker镜像

一般而言,当我们的程序开发完成后,会连同程序文件与运行环境一起制作成一个新的镜像。

要制作镜像,需要编写Dockerfile。DockeFile由多个命令组成,常用的命令有:

  • FROM:基于某个镜像来制作新的镜像。格式为:FROM 镜像名称:镜像版本。

  • COPY:从宿主机复制文件,支持?、*等通配符。格式为:COPY 源文件路径 目标文件路径。

  • ADD:从宿主机添加文件,格式与COPY相同,区别在于当文件为压缩文件时,会解压缩到目标路径。

  • RUN:在创建新镜像的过程中执行的shell命令。格式为:RUN shell命令行。注意,此shell命令将在容器内执行。

  • CMD:在容器实例中运行的命令,格式与RUN相同。注意,如果在docker run时指定了命令,将不会执行CMD的内容。

  • ENTRYPOINT:在容器实例中运行的命令,格式与CMD相同。注意,如果在docker run时指定了命令,该命令会以命令行参数的形式传递到ENTRYPOINT中。

  • ENV:在容器中创建环境变量,格式为:ENV 变量名值。

注意,Docker镜像中有一个层的概念,每执行一个RUN命令,就会创建一个层,层过多会导致镜像文件体积增大。尽量在RUN命令中使用&&连接多条shell命令,减少RUN命令的个数,可以有效减小镜像文件的体积。

5.1 自制显示文本文件内容镜像

编写cat.py,接收一个文件名,由python读取文件并显示文件的内容:

import os
import sysinput = sys.argv[1]with open(input, "r") as fp:print(fp.read())

这个例子比较简单,缩写Dockerfile如下:

FROM python:3.8
WORKDIR /files
COPY cat.py /cat.py
ENTRYPOINT ["python", "/cat.py"]

这个Dockerfile的含义是:

  1. 以python:3.8为基础镜像

  2. 容器启动命令的工作目录为/files,在运行镜像时,需要我们把宿主机的某目录挂载到容器的/files目录

  3. 复制cat.py到容器的根目录下

  4. 启动时运行python /cat.py命令

需要说明的是,ENTRYPOINT有两种写法:

ENTRYPOINT python /cat.py
ENTRYPOINT ["python", "/cat.py"]

这里采用第二种写法,是因为我们要在外部给容器传递参数。执行命令编译Docker镜像:

docker build -t cat:1.0 .

这个命令中,-t的含义是目标,即生成的镜像名为hello,版本号为1.0,别忘了最后那个.,这叫到上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

这样,我们的第一个镜像就制作完成了,使用下面的命令执行它:

docker run -it -v ~/docker_test/cat/files:/files cat:1.0 test.txt

即可看到~/docker_test/cat/files/test.txt的内容。

5.2 自制web服务器镜像

我们使用tornado开发一个网站,而python的官方镜像是没有tornado库的,这就需要在制作镜像时进行安装。

测试的ws.py如下:

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.webfrom tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("Hello world")if __name__ == "__main__":tornado.options.parse_command_line()app = tornado.web.Application(handlers=[(r"/", IndexHandler)])http_server = tornado.httpserver.HTTPServer(app)http_server.listen(options.port)tornado.ioloop.IOLoop.instance().start()

编写Dockerfile文件如下:

FROM python:3.8
WORKDIR /ws
COPY ws.py /ws/ws.py
RUN pip install tornado
CMD python hello.py

在此我们验证一下CMD与ENTRYPOINT的区别。在Dockerfile所在有目录下执行如下命令:

docker build -t ws:1.0 .

执行完成后,再使用docker images使用就可以看到生成的镜像了,然后使用下面的命令运行:

docker run -it -p 8000:8000 ws:1.0

在浏览器中输入宿主机的ip和8000端口,就可以看到页面了。

在这个例子中,我使用的运行命令是CMD,如果在docker run中指定的其他的命令,此命令就不会被执行,如:

$ docker run -it -p 8000:8000 ws:1.0 python
Python 3.8.7 (default, Dec 22 2020, 18:46:25) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

此时,容器中被执行的是python命令,而不是我们的服务。在更多情况下,我们希望在docker run命令中为我们的服务传参,而不是覆盖执行命令,那么,我们应该使用ENTRYPOINT而不是CMD:

FROM python:3.8
WORKDIR /ws
COPY ws.py /ws/ws.py
RUN pip install tornado
ENTRYPOINT python ws.py

上面这种写法,是不支持传递参数的,ENTRYPOINT和CMD还支持另一种写法:

FROM python:3.8
WORKDIR /ws
COPY ws.py /ws/ws.py
RUN pip install tornado
ENTRYPOINT ["python", "ws.py"]

使用这种写法,docker run命令中的参数才可以传递给hello.py:

docker run -it -p 8000:9000 ws:1.0 --port=9000

这个命令中,--port=9000被作为参数传递到hello.py中,因此容器内的端口就成了9000。

在生产环境中运行时,不会使用-it选项,而是使用-d选项,让容器在后台运行:

$ docker run -d -p 8000:9000 ws:1.0 --port=9000
4a2df9b252e2aff6a8853b3a8bf46c0577545764831bb7557b836ddcd85cba70
$ docker ps                                       
CONTAINER ID   IMAGE        COMMAND                  CREATED           STATUS            PORTS                    NAMES
4a2df9b252e2   hello:1.0    "python ws.py --p…"   9 seconds ago     Up 8 seconds      0.0.0.0:8000->9000/tcp   elegant_sammet

这种方式下,即使当前的控制台被关闭,该容器也不会停止。

5.3 自制apscheduler服务镜像

接下来,制作一个使用apscheduler编写的服务镜像,代码如下:

import sys
import shutil
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTriggerdef scan_files():shutil.copytree(sys[1], sys[2])scheduler = BlockingScheduler()
scheduler.add_job(scan_files,trigger=CronTrigger(minute="*"),misfire_grace_time=30
)

Dockerfile也是信手拈来:

FROM python:3.8
WORKDIR /
COPY sch.py /sch.py
RUN pip install apscheduler
ENTRYPOINT ["python", "sch.py"]

生成镜像:

docker build -t sch:1.0 .

应该可以运行了,文件复制需要两个目录,在运行时,可以使用两次-v来挂载不同的目录:

docker run -d -v ~/docker_test/sch/src:/src -v ~/docker_test/sch/dest:/dest sch:1.0 /src /dest

c08c2d7ac5ed306c5fe5357d78ef2ca7.png

多阶段构建压缩镜像体积

前面用到的官方python镜像大小足足882MB,在这个基础上,再安装用到的第三方库,添加项目需要的图片等资源,大小很容易就超过1个G,这么大的镜像,网络传给客户非常的不方便,因此,减小镜像的体积是非常必要的工作。

docker hub上有个一python:3.8-alpine镜像,大小只有44.5MB。之所以小,是因为alpine是一个采用了busybox架构的操作系统,一般用于嵌入式应用。我尝试使用这个镜像,发现安装一般的库还好,但如果想安装numpy等就会困难重重,甚至网上都找不到解决方案。

还是很回到基本的路线上来,主流的操作系统镜像,ubuntu的大小为72.9MB,centos的大小为209MB——这也算是我更喜欢使用ubuntu的一个重要原因吧!使用ubuntu作为基础镜像,安装python后的大小为139MB,再安装pip后的大小一下子上升到了407MB,要是再安装点其他东西,很容易就赶上或超过python官方镜像的大小了。

看来,寻常路线是很难压缩镜像文件体积了。幸好,还有一条曲线救国的路可走,这就是多阶段构建法。

多阶段构建的思想其实很简单,先构建一个大而全的镜像,然后只把镜像中有用的部分拿出来,放在一个新的镜像里。在我们的场景下,pip只在构建镜像的过程中需要,而对运行我们的程序却一点用处也没有。我们只需要安装pip,再用pip安装第三方库,然后将第三方库从这个镜像中复制到一个只有python,没有pip的镜像中,这样,pip占用的268MB空间就可以被节省出来了。

1、在ubuntu镜像的基础上安装python:

FROM ubuntu
RUN apt update \&& apt install python3

然后运行:

docker build -t python:3.8-ubuntu .

这样,就生成了python:3.8-ubuntu镜像。

2、在python:3.8-ubuntu的基础上安装pip:

FROM python:3.8-ubuntu
RUN apt install python3

然后运行:

docker build -t python:3.8-ubuntu-pip .

这样,就生成了python:3.8-ubuntu-pip镜像。

3、多阶段构建目标镜像:

FROM python:3.8-ubuntu-pip
RUN pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
FROM python:3.8-ubuntu
COPY --from=0 /usr/local/lib/python3.8/dist-packages/ /usr/local/lib/python3.8/dist-packages/

这个dockerfile需要解释一下了,因为它有两个FROM命令。

第一个是以python:3.8-ubuntu-pip镜像为基础,安装numpy,当然,在实际应用中,把所有用到的第三方库出写在这里。

第二个FROM是以FROM python:3.8-ubuntu镜像为基础,将第三方库统统复制过来,COPY命令后的–from=0的意思是从第0阶段进行复制。实际应用中再从上下文中复制程序代码,添加需要的ENTRYPOINT等。

最后,再运行:

docker build -t project:1.0 .

这然,用于我们项目的镜像就做好了。比使用官方python镜像构建的版本,小了大约750MB。

b199eb04652a85cdf254fa1bb0850eeb.png

导入镜像到生产环境

到此,我们的镜像已经制作好了,可是,镜像文件在哪,如何在生产环境下运行呢?

刚才使用docker images命令时,已经看到了生成的镜像:

$ docker images                          
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               1.0                 01fe19111dc7        59 minutes ago      893MB
python              3.8                 f5041c8ae6b1        13 days ago         884MB
ubuntu              20.04               f643c72bc252        5 weeks ago         72.9MB
hello-world         latest              bf756fb1ae65        12 months ago       13.3kB

我们可以使用docker save命令将镜像保存到指定的文件中,保存的文件是一个.tar格式的压缩文件:

docker save -o hello.tar hello:1.0

将hello.tar复制到生产环境的机器上,然后执行导入命令:

docker load -i hello.tar

就可以使用了。

70ebd5e05cdadc110f8be130b0446844.gif

往期推荐

如果让你来设计网络

70% 开发者对云原生一知半解,“云深”如何知处?

浅述 Docker 的容器编排

如何在 Kubernetes Pod 内进行网络抓包

f2ecf171ee472cd8c12587ac4f91b1a1.gif

点分享

5a8b454f839869d709ec18288f210923.gif

点收藏

6bc2049d5c85a8847c7dbf546f131b98.gif

点点赞

9559604d0a1797230af0697170eea319.gif

点在看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/511953.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux phpunit 安装,在CentOS 7/CentOS 8系统中安装PHPUnit的方法

本文介绍在CentOS 7/CentOS 8操作系统中安装PHPUnit的方法&#xff0c;只需要运行几个命令就可以了&#xff0c;非常的简单。PHPUnit是PHP应用程序的单元测试框架&#xff0c;它是单元测试框架的xUnit体系结构的一个实例&#xff0c;它在JUnit中很受欢迎&#xff0c;PHPUnit需要…

解读如何安全快速建立IT治理环境

简介&#xff1a;云计算经过十多年的发展&#xff0c;从基础的IAAS&#xff0c;大数据&#xff0c;到各种的PaaS有丰富的产品和生态&#xff0c;非常有效地助力了业务增长和技术创新&#xff0c;并提高了业务的效率。最直观的感受是过去需要几天到一个月的资源交付&#xff0c;…

com+ system application 启动_dubbo启动引导过程(基于2.7.9)

前言再百度或google上一搜索dubbo服务暴露过程 相关的文章已经有很多了&#xff0c;但是文章基本都是基于老版本的dubbo&#xff0c;当你对着文章去看下载下来的代码时&#xff0c;会发现很多东西对不上&#xff1b;出于此目的&#xff0c;我便有了自己根据新版本&#xff08;就…

函数计算 GB 镜像秒级启动:下一代软硬件架构协同优化

简介&#xff1a;本文将介绍借助函数计算下一代 IaaS 底座神龙裸金属和安全容器&#xff0c;进一步降低绝对延迟且能够大幅降低冷启动频率。 作者&#xff1a;修踪 背景 函数计算在 2020 年 8 月创新地提供了容器镜像的函数部署方式。AWS Lambda 在 2020 年 12 月 Re-Invent…

为什么服务端程序都需要先 listen 一下?

作者 | 张彦飞allen来源 | 开发内功修炼大家都知道&#xff0c;在创建一个服务器程序的时候&#xff0c;需要先 listen 一下&#xff0c;然后才能接收客户端的请求。例如下面的这段代码我们再熟悉不过了。int main(int argc, char const *argv[]) {int fd socket(AF_INET, SOC…

10个Bug环环相扣,你能解开几个?

简介&#xff1a;由阿里云云效主办的2021年第3届83行代码挑战赛已经收官。超2万人围观&#xff0c;近4000人参赛&#xff0c;85个团队组团来战。大赛采用游戏闯关玩儿法&#xff0c;融合元宇宙科幻和剧本杀元素&#xff0c;让一众开发者玩得不亦乐乎。 今天请来决赛赛题设计者…

小小智慧树机器人_国网营业厅“AI新势力”,科沃斯商用机器人解锁智慧服务新模式!...

智慧营业厅新格局&#xff0c;AI机器人成标配&#xff1f;AI加持&#xff0c;万物互联、万物智能。2019年&#xff0c;应用人工智能的门槛下降&#xff0c;大量人工智能催生的新产品、服务和最佳实践轮番出现。人工智能正在重塑各行各业&#xff0c;传统营业厅网点该如何搭上AI…

AIoT时代存储如何升级?长江存储发布高速闪存芯片UFS 3.1

2022年4月19日&#xff0c;长江存储科技有限责任公司&#xff08;简称“长江存储”&#xff09;宣布推出UFS 3.1通用闪存——UC023。这是长江存储为5G时代精心打造的一款高速闪存芯片&#xff0c;可广泛适用于高端旗舰智能手机、平板电脑、AR/VR等智能终端领域&#xff0c;以满…

零信任策略下云上安全信息与事件管理实践

简介&#xff1a;随着企业数字化转型的深入推进&#xff0c;网络安全越来越被企业所重视。为了构建完备的安全防御体系&#xff0c;企业通常会引入了防火墙(Firewall)、防病毒系统(Anti-Virus System&#xff0c;AVS)、入侵防御系统(Intrusion Prevention System&#xff0c;IP…

kl散度度量分布_数据挖掘比赛技巧——确定数据同分布

在数据挖掘比赛中&#xff0c;很重要的一个技巧就是要确定训练集与测试集特征是否同分布&#xff0c;这也是机器学习的一个很重要的假设[1]。但很多时候我们知道这个道理&#xff0c;却很难有方法来保证数据同分布&#xff0c;这篇文章就分享一下我所了解的同分布检验方法。封面…

Inclavare Containers:云原生机密计算的未来

简介&#xff1a;本文为你详细的梳理一次 Inclavare Containers 项目的发展脉络&#xff0c;解读它的核心思想和创新技术。 作为业界首个面向机密计算场景的开源容器运行时&#xff0c;Inclavare Containers 项目于 2020 年 5 月开源&#xff0c;短短一年多时间内发展势头非常迅…

没有操作系统程序可以运行起来吗?

作者 | 陆小风来源 | 码农的荒岛求生现在的程序员对操作系统已经习以为常了&#xff0c;但是你有没有想过&#xff0c;如果没有操作系统的话我们可以让程序运行起来吗&#xff1f;先说答案&#xff0c;当然是可以的&#xff0c;而且必须是可以的。你可以从这个角度来思考&#…

sysAK(青囊)系统运维工具集:如何实现高效自动化运维?| 龙蜥技术

简介&#xff1a;What is sysAK、典型工具介绍、开源 3 方面介绍了 sysAK 系统&#xff0c;目前 sysAK 工具集已经在龙蜥社区开源&#xff0c;并且在系统运维 SIG、跟踪诊断 SIG 一起共建&#xff0c;希望大家后期加入 SIG 一起讨论共建。 编者按&#xff1a;本文整理自「云栖…

quill鼠标悬浮 出现提示_CHERRY MC8.1鼠标评测:超前设计延续军火箱信仰

CHERRY作为机械键盘品牌拥有非常高的知名度&#xff0c;许多朋友的第一把机械键盘就是CHERRY品牌。在CHERRY产品线中&#xff0c;最具信仰的一定是军火箱MX8.0键盘。键盘本身手感颜值俱佳&#xff0c;独特的军火箱包装更是收获了大批粉丝。至于最配这把键盘的鼠标却一直让网友们…

高并发IO的底层原理

作者 | 阿辉来源 | Andy阿辉思考&#xff1a;作为程序员的我们&#xff0c;在编写软件进行文件读取&#xff0c;网络收发数据时&#xff0c;是不关心其具体的内部数据传输的。只关心把数据传输到缓冲区或及时从缓冲区读取数据。那么内部究竟是如何实现的呢&#xff0c;今天这篇…

新能源汽车太猛了,这些卡脖子技术你了解吗?

简介&#xff1a;从汽车行业的变化&#xff0c;我们即可初步看出芯片的重要性&#xff0c;那么&#xff0c;芯片对汽车行业的发展具体有哪些重要影响呢&#xff1f; 根据全球汽车咨询机构Auto Forecast Solutions统计的数据&#xff0c;截至10月10日&#xff0c;由于芯片短缺&…

龙蜥社区成立系统运维SIG,开源sysAK系统运维工具集

简介&#xff1a;系统运维SIG致力于打造一个集主机管理、配置部署、监控报警、异常诊断、安全审计等一系列功能的自动化运维平台。 OpenAnolis 龙蜥社区&#xff08;以下简称“龙蜥社区”&#xff09;正式成立系统运维&#xff08;System Operation&Maintenance, sysOM&…

奔跑吧兄弟变成机器人是哪一期_奔跑吧预告,郑恺郭麒麟回归,而我却被女嘉宾的颜值吸引了...

哈喽小伙伴们&#xff0c;近期大家都看了《奔跑吧黄河篇》吗&#xff1f;现在已经播到第二期了&#xff0c;相信大家依旧是对跑男系列节目非常感兴趣的&#xff0c;播放量非常高&#xff0c;稳稳占据TX和AQY两大视频平台的综艺播放第一名的位置&#xff0c;可见网友们真的是非常…

院士专家热议如何拥抱“东数西算”,第二届中国IDC行业Discovery大会顺利召开

4月21日&#xff0c;一场别开生面的主题为“聚光奔赴”的数据中心行业大会圆满落下帷幕。由中国通信工业协会数据中心委员会指导&#xff0c;中国IDC圈与世纪互联共同主办的“2022年第二届中国IDC行业Discovery大会”在线上召开&#xff0c;会议聚焦国家“双碳”目标、“东数西…

一文理解 K8s 容器网络虚拟化

简介&#xff1a;本文需要读者熟悉 Ethernet&#xff08;以太网&#xff09;的基本原理和 Linux 系统的基本网络命令&#xff0c;以及 TCP/IP 协议族并了解传统的网络模型和协议包的流转原理。文中涉及到 Linux 内核的具体实现时&#xff0c;均以内核 v4.19.215 版本为准。 作者…