docker

preface

Recently, WHEN I was researching cloud development, I came into contact with Docker, so I had a brief understanding and took notes of the practical operation in these days.

What is the docker

There are a lot of relevant materials on the Internet. According to my understanding, the core of Docker is the image and container. The image realizes encapsulation, while the container realizes environmental isolation.

Deployment project

  • vue
  • nodejs
  • mysql

The preparatory work

  • To register the mirror repository, I usehttps://hub.docker.com/, can also use ali cloud mirror warehouse, used to save our mirror
  • The installationdockerThere are many tutorials on the Internet.windowInstallation is troublesome (some notes will be mentioned at the end of this article),macThe installationdocker desktopCan,linuxInstallation is simple.

The mirror

We started with the most basic image packaging, and now I have a VUE project ready to deploy to the server

  • Created in the project root directoryDockerfileanddefault.confFile, as follows
# Dockerfile
# must, based on the official Nginx image, in order to deploy the service
FROM nginx
# Optional, specify
MAINTAINER website-library
Remove the default nginx configuration
RUN rm /etc/nginx/conf.d/default.conf
# Use the nginx configuration we defined
ADD default.conf /etc/nginx/conf.d/
Copy the files in dist
COPY dist/ /usr/share/nginx/html/
Copy the code
# default.conf
server {
    listen       80;
    server_name  localhost; Change to the HOST IP of the Docker service
    
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html =404;
    }
    
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        roothtml; }}Copy the code
  • Package the project and execute the commandDocker build-t Specifies the image name.Don’t forget the back.Change the image name to the name you want
  • A full mirror name should be[mirror name]/[mirror name]:[tag]If you want to push to a mirror repository, the image name is required; When you need to indicate the version of the current image or other information,tagIf tag is omitted, it defaults to taglatest
  • For example, the name of my mirror repository is Chakcheung, and I want the image to be identified as version 1, so I can package the image in one step.docker build -t chakcheung/vuedemo:v1 .Of course, the back can be changed.
  • Execute the command at this timedocker imagesordocker image ls, you can see a list of mirrors
  • Next I want to test the image, execute the commanddocker run -p 8080:80 -d --restart=always chakcheung/vuedemo:v1If the operation succeeds, the terminal will feedback the container ID
  • Execute the commanddocker psIf the container ID is not displayed, an error message may be sent. Run the commanddocker ps -aYou can see that all containers, including those that are not running, execute commandsDocker logs container ID, you can print logs about container execution to locate errors.
  • If the execution succeeds, you can open a browser and visitlocalhost:8080It should be possible to see the project running properly.
  • Let’s unpack the command that runs the image
    • -pThis parameter represents the access to port 8080 of the server, mapped to port 80 of the container, where we have deployed the project
    • -dBackground running
    • --restart=alwaysIndicates automatic restart

Push the mirror

  • With the image packaged, we can then push it to our remote library
  • Execute the commandDocker login --username= repository name, enter the password. The system returns after successful loginLogin Succeeded
  • Execute the commanddocker push chakcheung/vuedemo:v1To push the image to the repository
  • If you did not include the repository name when packing the image, run the commandDocker tag [docker tag], mark the image and put it in the warehouse
  • Execute the commanddocker image lsYou can see that there is an extra image and push it to the remote library
  • Open the address of the remote library, or opendocker desktopYou can see the image we just pushed in the image list

Pull the image and deploy the service

  • Go to the server and run the commanddocker pull chakcheung/vuedemo:v1If you are already logged in
  • You can see that there is an extra record in the image list. Next we will deploy this image to the server9500port
  • performdocker run -p 9500:80 -d --restart=always chakcheung/vuedemo:v1
  • performdocker psCheck whether it runs successfully
  • At this point, the deployment is successful and the server can be accessed9500Port, see the deployed project

docker-compose

  • Following the above operation, we can putnodejsThe project andmysqlAll deployed on the server
  • nodejstheDockerfileIt’s pretty much the same, as follows
      # Use official Node.js 12 lightweight images.
      FROM node:12-slim
      Define the working directory
      WORKDIR /usr/src/app
      Copy the dependency definition file to the working directory
      COPY package*.json ./
      Install dependencies in production form
      RUN npm install --only=production
      Copy the local code to the working directory
      COPY . ./
      # start service
      CMD [ "npm"."run"."start" ]
    Copy the code
  • mysqlYou can pull the official image from the server and run the commanddocker run --name mysql-demo -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d --restart=always mysqlStart to
  • You can certainly do this by packaging, pushing, pulling, launching, mirror by mirror, and then repeatedly packaging, pushing, pulling, removing containers, and launching each time you update the code. But have you ever wondered if there’s a tool that can help you do these things, and that isdocker-compose
  • docker-composeBased on theymlScripts can manage our images and containers very well, and documents can be searched by themselves
  • The installationdocker-compose.windowsandmacThe installationdockerWill be installed at the same time,linuxYou need to install it yourself
  • Find a directory and store itymlFile, execute commandvim docker-compose.ymlcreateymlThe file name is optional and the content is as follows
# Use version
 version: "3"
    # Service list
    services:
      vuedemo:
        The image used can also specify the packaging script via dockerfile
        image: chakcheung/vuedemo:v1
        # port mapping
        ports:
          - "9500:80"
      mysql:
        image: mysql
        ports:
          - "3306:3306"
        # folder mapping
        volumes:
          - /data/mysql/data/:/var/lib/mysql/
          - /data/mysql/conf/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
        # Environment variables
        environment:
          - MYSQL_ROOT_PASSWORD=123456
          - LANG=C.UTF-8
      backend:
        image: chakcheung/backend
        ports:
          - "1333:1333"
Copy the code
  • Then, in theymlRun commands in the directory where the command residesdocker-compose pullThis command will package or pull all images required by the service, followed by the commanddocker-compose up -d, the command will be based onymlStart the service
    • Of course, both commands can pass-fThe specifiedymlfile
    • docker-compose upYou can declare--force-recreateForce the service to be rebuilt, otherwise the service will not be rebuilt if the image is not updated
  • At this point, you can execute commandsdocker ps -aLooking at the execution of the services, all three services should be successfully executed
  • Later our code updated, just need to update the image, and then to the server, execute the commanddocker-compose pull.docker-compose up -dThat’s it, silky!

dockerize

In the previous step, you may not be able to slide down, and some services may fail to start. For example, if backend attempts to connect to the database during startup, it may fail to connect to the database and report an error. This is a project dependency problem. There are different solutions to this problem

  • dockerizeProvide parameters that allow us to wait for a service to complete startup before performing operations
  • Start by sorting out the project dependencies,vuedemoBasically independent of the other two,backendBecause it’s initialized at startupmysqlThe connection, so we have to waitmysqlAfter the startup is complete, start againbackendThat is, we will be inbackendThe start command of this container is executeddockerize, let’s modify itymlFile,backendTo add the execution command
  backend:
    image: chakcheung/backend
    ports:
      - "1333:1333"
    command: ["dockerize"."-wait"."tcp://mysql:3306"."-timeout"."1800s"."npm"."run"."start:prod"]
Copy the code
  • -waitIndicates waiting for a service.-timeoutIndicates the number of seconds after the timeout; This is followed by the command executed after success
  • But if you just do it, you’ll seedockerizeIt cannot be found because the command does not exist in the container, we will install it in the containerdockerizeAt this point you might want to go into a container and install it,dockerAlso providesexecandattachThe method lets us enter the container, but in doing so, we will have to repeat to install the container every time we update, that is not possible, since the image does not exist, we will create a mirror!

To make the mirror

These are the problems I encountered in the process of learning, but also their own solutions, if there is a better way, please mercilessly laugh at, and then teach me.

  • The originalbackendIt’s officialnode:12-slimSo we can encapsulate a tape based on this imagedockerizeThe mirror image of
  • Execute the commanddocker pull node:12-slim
  • Execute the commanddcoker run -ti node:12-slim /bin/bash, runs and enters the container
  • Once in the container, since it is the Mini version, to install some packages, execute the command
    • apt-get update
    • apt-get upgrade
    • apt-get wget
  • The installationdockerize
Wget https://github.com/jwilder/dockerize/releases/download/v0.6.1/dockerize-alpine-linux-amd64-v0.6.1.tar.gz \ && tar -C /usr/local/bin - XZVF dockerize-alpine linux-amd64-v0.6.1.tar.gz \ && rm dockerize-alpine linux-amd64-v0.6.1.tar.gzCopy the code
  • exitOut of the container
  • performInit docker commit -m "commit" -a "chak" container id chakcheung/node: dockerize
  • There will be a new record in the mirror list, which can be pushed to the repository
  • Modify thebackendtheDockerfile
# using encapsulation of mirror FROM chakcheung/node: dockerize # define working directory WORKDIR/usr/SRC/app # will depend on the definition file COPY to working directory COPY package *. Json. / # to CMD [" NPM ", "RUN ", "start:prod"]Copy the code
  • Repackage the image and push it to the server, performing pull and up
  • When complete, execute the commandDocker logs container IDTo viewbackendRun log, you can see
2021/07/28 07:51:46 Problem with dial: dial TCP 172.19.0.3:3306: Sleeping 1s 2021/07/28 07:51:47 Problem with dial: dial 172.19.0.3:3306: connect connection refused. Sleeping 1s 2021/07/28 07:51:48 Connected to tcp://mysql:3306Copy the code
  • inmysqlThe deployment starts after the service is deployedbackend, which solves the problem of service dependency

Some of the problems

Windows installation docker

On Windows, this error usually occurs after Docker is installed

error during connect: In the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect.: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/containers/json: open / /. / pipe/docker_engine: The system cannot find the file specified.Copy the code

It seems that docker only supports the Linux kernel, and the online solution does not apply to me. Although many people say that it has been solved, it has always been the same error

CD "C: Program Files\Docker\Docker"./ dockercli. exe -switchdaemonCopy the code

So I had to find another way, CMD and Powershell could not start properly, so I tried the Linux kernel, just recently upgraded the system to support WSL2, so I installed WSL2 and Ubuntu 20.04 distribution, in Ubuntu terminal, successfully executed the docker command

# Windows Subsystem Installation Guide for Linux (Windows 10) https://docs.microsoft.com/zh-cn/windows/wsl/install-win10#manual-installation-steps # for Linux Windows Subsystem distribution package (Microsoft Store is unavailable, can download) on the https://docs.microsoft.com/zh-cn/windows/wsl/install-manualCopy the code

Mysql8 connection error

This error may occur when connecting to versions higher than mysql8

Client does not support authentication protocol requested by server; consider upgrading MySQL client
Copy the code

The reason is that before MySQL8, the encryption rule was mysql_native_password, and after MySQL8, the encryption rule is caching_sha2_password, The usual solution is to restore the mysql user password encryption rules to mysql_native_password, so you can either lower the version or change the encryption rules. I chose to keep version 8

  • performDocker exec -it Container ID /bin/bashEnter the container and execute the commandmysql -u root -pLog on to the mysql
# execute in sequence
ALTER USER 'root'@The '%' IDENTIFIED BY 'New password' PASSWORD EXPIRE NEVER;
ALTER USER 'root'@The '%' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY 'New password';
# to restart
FLUSH PRIVILEGES;
Copy the code
  • Exit and reconnect
  • But by doing so, it means ifmysqlThe container is destroyed and we have to do it again when we rebuild it, which is a hassle, although mysql images are not easily rebuilt
  • But I can’t stand it, so I’ll stick to itdockerizeThe same method is based on the officialmysqlI made a mirror image of myself

Nginx deployment issues

I encountered a problem during deployment that I wanted to proxy to my VUE project when accessing the Web directory on port 9502, i.e

Proxy to a service deployed on port 9500 when accessing localhost:9502 or localhost:9502/web or localhost:9502/web/Copy the code
# This is my configuration
 server {
    listen      9502;
    server_name localhost;
    location /    {
      rewrite    ^ / $ http://$host:9502/web/;
    }
    location /web {
      rewrite     ^/web$ http://$host:9502/web/;
      proxy_passhttp://127.0.0.1:9500/; }}Copy the code
  • I didn’t get it at first. I thought9502/web/The agent to9500, will read the current directoryindex.htmlAnd other resources, and it took a few tries to find out whenindex.htmlWhen reading other resources, it is actually askinglocalhost:9502/xxxThe request was made, so it could not be read
  • Having figured that out, I putvue.config.jsthepublicPathTo value/webSo that theindex.htmlWhen reading other resources, it is directed tolocalhost:9502/web/xxxInitiate a request, and it will be proxyed9500Under the
  • Without contact, it will be strange, or to see and learn more