$ docker pull ubuntu:18.04
创建容器并挂载共享文件夹。
$ docker run -v /run/media/duapple/Data/project:/media/shared -itd --name web_server ubuntu:18.04 /bin/bash
$ docker exec -it web_server /bin/bash
# useradd -d /home/duapple -m duapple
# passwd duapple
添加用户组
# usermod -g duapple -G root duapple
使用sudo
# apt update
# apt install sudo vim
# chmod u+w /etc/sudoers
# vim /etc/sudoers
添加
root ALL=(ALL:ALL) ALL
duapple ALL=(ALL:ALL) ALL
# chmod u-w /etc/sudoers
修改该用户的默认shell
为 bash
。(不修改会导致很多命令不能用)
# usermod -s /bin/bash duapple
新建 /home/duapple/.bashrc
文件。
#
# ~/.bashrc
#
export PATH=$PATH:/opt/arm-2014.05/bin
[[ $- != *i* ]] && return
colors() {
local fgc bgc vals seq0
printf "Color escapes are %s\n" '\e[${value};...;${value}m'
printf "Values 30..37 are \e[33mforeground colors\e[m\n"
printf "Values 40..47 are \e[43mbackground colors\e[m\n"
printf "Value 1 gives a \e[1mbold-faced look\e[m\n\n"
# foreground colors
for fgc in {30..37}; do
# background colors
for bgc in {40..47}; do
fgc=${fgc#37} # white
bgc=${bgc#40} # black
vals="${fgc:+$fgc;}${bgc}"
vals=${vals%%;}
seq0="${vals:+\e[${vals}m}"
printf " %-9s" "${seq0:-(default)}"
printf " ${seq0}TEXT\e[m"
printf " \e[${vals:+${vals+$vals;}}1mBOLD\e[m"
done
echo; echo
done
}
[ -r /usr/share/bash-completion/bash_completion ] && . /usr/share/bash-completion/bash_completion
# Change the window title of X terminals
case ${TERM} in
xterm*|rxvt*|Eterm*|aterm|kterm|gnome*|interix|konsole*)
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/\~}\007"'
;;
screen*)
PROMPT_COMMAND='echo -ne "\033_${USER}@${HOSTNAME%%.*}:${PWD/#$HOME/\~}\033\\"'
;;
esac
use_color=true
# Set colorful PS1 only on colorful terminals.
# dircolors --print-database uses its own built-in database
# instead of using /etc/DIR_COLORS. Try to use the external file
# first to take advantage of user additions. Use internal bash
# globbing instead of external grep binary.
safe_term=${TERM//[^[:alnum:]]/?} # sanitize TERM
match_lhs=""
[[ -f ~/.dir_colors ]] && match_lhs="${match_lhs}$(<~/.dir_colors)"
[[ -f /etc/DIR_COLORS ]] && match_lhs="${match_lhs}$(</etc/DIR_COLORS)"
[[ -z ${match_lhs} ]] \
&& type -P dircolors >/dev/null \
&& match_lhs=$(dircolors --print-database)
[[ $'\n'${match_lhs} == *$'\n'"TERM "${safe_term}* ]] && use_color=true
if ${use_color} ; then
# Enable colors for ls, etc. Prefer ~/.dir_colors #64489
if type -P dircolors >/dev/null ; then
if [[ -f ~/.dir_colors ]] ; then
eval $(dircolors -b ~/.dir_colors)
elif [[ -f /etc/DIR_COLORS ]] ; then
eval $(dircolors -b /etc/DIR_COLORS)
fi
fi
if [[ ${EUID} == 0 ]] ; then
PS1='\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] '
else
PS1='\[\033[01;32m\][\u@\h\[\033[01;37m\] \W\[\033[01;32m\]]\$\[\033[00m\] '
fi
alias ls='ls --color=auto'
alias grep='grep --colour=auto'
alias egrep='egrep --colour=auto'
alias fgrep='fgrep --colour=auto'
else
if [[ ${EUID} == 0 ]] ; then
# show root@ when we don't have colors
PS1='\u@\h \W \$ '
else
PS1='\u@\h \w \$ '
fi
fi
unset use_color safe_term match_lhs sh
alias cp="cp -i" # confirm before overwriting something
alias df='df -h' # human-readable sizes
alias free='free -m' # show sizes in MB
alias np='nano -w PKGBUILD'
alias more=less
alias proxyyay="ALL_PROXY=socks://localhost:1089 yay "
alias grepf="grep -R -n -s"
alias findc="find . -name \"*.c\" | xargs grep -n -s "
alias findh="find . -name \"*.h\" | xargs grep -n -s "
alias finda="find . -name \"*\" | xargs grep -n -s "
alias rmts="mv -t ~/.mytrash "
xhost +local:root > /dev/null 2>&1
complete -cf sudo
# Bash won't get SIGWINCH if another process is in the foreground.
# Enable checkwinsize so that bash will check the terminal size when
# it regains control. #65623
# http://cnswww.cns.cwru.edu/~chet/bash/FAQ (E11)
shopt -s checkwinsize
shopt -s expand_aliases
# export QT_SELECT=4
# Enable history appending instead of overwriting. #139609
shopt -s histappend
#
# # ex - archive extractor
# # usage: ex
ex ()
{
if [ -f $1 ] ; then
case $1 in
*.tar.bz2) tar xjf $1 ;;
*.tar.gz) tar xzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar x $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xf $1 ;;
*.tbz2) tar xjf $1 ;;
*.tgz) tar xzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1;;
*.7z) 7z x $1 ;;
*) echo " '$1' cannot be extracted via ex()" ;;
esac
else
echo "'$1' is not a valid file"
fi
}
重启终端或者 source /home/duapple/.bashrc
生效。
需要编译环境请安装 gcc
, make
。
$ sudo apt install net-tools iputils-ping gcc make
$ sudo systemctl stop docker
修改 /var/lib/docker/containers/[容器ID]
下的 config.v2.json
和 hostconfig.json
配置文件中对应的挂载选项。修改 /run/media/duapple/Data/project
为我们需要挂载的主机目录。修改成功后,重启docker服务。
{
"StreamConfig": {},
"State": {
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"RemovalInProgress": false,
"Dead": false,
"Pid": 0,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-05-07T16:02:38.36826019Z",
"FinishedAt": "2022-05-07T16:04:10.879309771Z",
"Health": null
},
"ID": "92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195",
"Created": "2022-05-06T14:18:07.32273477Z",
"Managed": false,
"Path": "/bin/bash",
"Args": [],
"Config": {
"Hostname": "92788eda9c8d",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": true,
"OpenStdin": true,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "ubuntu:18.04",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"Image": "sha256:c6ad7e71ba7d4969784c76f57c4cc9083aa96bb969d802f2ea38f4aaed90ff93",
"NetworkSettings": {
"Bridge": "",
"SandboxID": "2a9c29965b238576d16aeea8e4c02b838664a016220f198f22639c58a4236445",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "2d8b901aba177354671a1b494bcba27559f5ec7d390a8adf37fff3129695d280",
"EndpointID": "",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null,
"IPAMOperational": false
}
},
"Service": null,
"Ports": null,
"SandboxKey": "/var/run/docker/netns/2a9c29965b23",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"IsAnonymousEndpoint": false,
"HasSwarmEndpoint": false
},
"LogPath": "/var/lib/docker/containers/92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195/92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195-json.log",
"Name": "/web_server",
"Driver": "overlay2",
"OS": "linux",
"MountLabel": "",
"ProcessLabel": "",
"RestartCount": 0,
"HasBeenStartedBefore": true,
"HasBeenManuallyStopped": true,
"MountPoints": {
"/media/shared": {
"Source": "/run/media/duapple/Data/project",
"Destination": "/media/shared",
"RW": true,
"Name": "",
"Driver": "",
"Type": "bind",
"Propagation": "rprivate",
"Spec": {
"Type": "bind",
"Source": "/run/media/duapple/Data/project",
"Target": "/media/shared"
},
"SkipMountpointCreation": false
}
},
"SecretReferences": null,
"ConfigReferences": null,
"AppArmorProfile": "docker-default",
"HostnamePath": "/var/lib/docker/containers/92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195/hostname",
"HostsPath": "/var/lib/docker/containers/92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195/hosts",
"ShmPath": "",
"ResolvConfPath": "/var/lib/docker/containers/92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195/resolv.conf",
"SeccompProfile": "",
"NoNewPrivileges": false,
"LocalLogCacheMeta": {
"HaveNotifyEnabled": false
}
}
{
"Binds": [
"/run/media/duapple/Data/project:/media/shared"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "private",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": null,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
}
修改 "Privileged": true,
,使容器获得真正的root权限,否则挂载网络共享文件夹会失败。
重启服务。
$ systemctl start docker.service
挂载网络文件夹
也需要运行参数 "Privileged": true,
。
$ sudo apt install nfs-common
$ sudo mount -t nfs4 -o nolock 172.17.0.1:/home/duapple/share /home/duapple/shared/
安装。
$ sudo apt install mosquitto mosquitto-clients
$ sudo service mosquitto start
测试。
$ mosquitto_sub -h localhost -t test
$ mosquitto_pub -h localhost -t test -m "helloworld"
配置密码。
$ sudo mosquitto_passwd -c /etc/mosquitto/passwd monitor_client
$ sudo vim /etc/mosquitto/conf.d/default.conf
添加:
allow_anonymous false
password_file /etc/mosquitto/passwd
重启docker容器。
重启mosquitto。
$ sudo mosquitto -c /etc/mosquitto/mosquitto.conf
$ sudo service mosquitto restart
如果不加 -u
和 -P
参数,即用户参数鉴权参数,将导致一下错误。
Connection Refused: not authorised.
Error: The connection was refused.
需要将主机的端口映射到docker容器,其中包含我们应用需要使用到的。Web端口,RTMP端口,MQTT端口。
在hostconfig.json
和 config.v2.json
中进行配置。
参考:https://cloud.tencent.com/developer/article/1833131
$ sudo systemctl stop docker.service
# kate /var/lib/docker/containers/92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195/hostconfig.json
# kate /var/lib/docker/containers/92788eda9c8d03533096a0387d39097626c2223bef6bf37b16d9642340743195/config.v2.json
修改 hostconfig.json
文件的 PortBindings
参数,如下:
"PortBindings":{"1883/tcp":[{"HostIp":"","HostPort":"1883"}],"1935/tcp":[{"HostIp":"","HostPort":"1935"}],"80/tcp":[{"HostIp":"","HostPort":"80"}],"8080/tcp":[{"HostIp":"","HostPort":"8000"}]}
修改 config.v2.json
,在 "AttachStderr":false,
参数后添加如下参数,与hostconfig.json
中的设置对应:
"ExposedPorts":{"1883/tcp":{},"1935/tcp":{},"80/tcp":{},"8080/tcp":{}}
重启docker,当上述参数修改的格式不对时,将导致docker容器启动失败。
$ sudo systemctl start docker.service
$ docker start web_server
在容器中启动nginx后,再在主机浏览器访问localhost:80,即可验证端口映射是否修改成功。
注意:当没有关闭docker服务,就修改配置,会导致配置修改无效。
编译配置好nginx。
解压 nginx-1.18.0.tar.gz
和 nginx-http-flv-module.tar.gz
到同一路径。
$ sudo apt install openssl pcre-devel openssl openssl-devel libpcre3 libpcre3-dev libssl-dev zlib1g-dev
$ cd nginx-1.18.0
$ ./configure --prefix=/usr/local/nginx --add-module=$(pwd)/../nginx-http-flv-module
$ make -j12
$ sudo make install
$ sudo ln -s /usr/local/nginx/sbin/nginx /usr/bin/
$ sudo nginx -c /usr/local/nginx/conf/nginx.conf
$ sudo nginx -s reload
$ sudo nginx -t
修改 /usr/local/nginx/conf/nginx.conf
配置。并拷贝 stat.xsl
到指定位置 /var/www/rtmp
。
$ sudo cp nginx-http-flv-module/stat.xsl /usr/www/rtmp
配置教程:https://beego.vip/docs/deploy/nginx.md
将上述配置好的容器打包程docker镜像,在服务器上导入。
服务器安装docker。
$ curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
$ docker -h
配置docker不使用sudo:https://blog.csdn.net/boling_cavalry/article/details/106590784
打包本地主机的docker镜像,并上传到云服务器。
$ docker export web_server -o ubuntu1804_webserver.tar
导入docker镜像。
$ cat ubuntu1804_webserver.tar |docker import - ubuntu1804
创建docker容器。
$ docker run -p 80:80 -p 8080:8080 -p 1935:1935 -p 1883:1883
--privileged=true -v /home/ubuntu/shared:/home/duapple/shared -itd --name web_server ubuntu1804 /bin/bash
$ docker exec -it web_server su - duapple
在容器中启动nginx和应用即可正常访问。
需要设置第一个启动的进程为 /sbin/init
,修改 config.v2.json
中的 /bin/bash
为 /sbin/init
,需要先关闭docker服务。容器内需要安装 systemd
。
以下为执行成功。
$ [duapple@cef5d671d63d ~]$ sudo systemctl enable mosquitto
[sudo] password for duapple:
mosquitto.service is not a native service, redirecting to systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable mosquitto
添加自定义服务,在 /lib/systemd/system
下新建 monitor_server.service
文件。添加如下内容:
[Unit]
Description=monitor_server
[Service]
Type=simple
ExecStart=/home/duapple/app/monitor_server/monitor_server
Restart=on-failure
RestartSec=20s
WorkingDirectory=/home/duapple/app/monitor_server
[Install]
WantedBy=multi-user.target
生效配置,设置开机启动并启动web应用。
$ sudo systemctl daemon-reload
$ sudo systemctl enable monitor_server
$ sudo systemctl start monitor_server
完成,可以访问了 : )