Private projects use github action to package docker images and deploy them to servers
Tags: docker, githubactions, frontend, deploy
Published: 2023-06-01 08:11:36

> There are always some projects that don't want to be open source. For the convenience of deployment, they hope to automatically deploy to different servers through docker after the code is changed. This article briefly describes the whole process, I hope it will help you

## 1. First create a project

First create a private project on github ![](https://cdn-1252273386.cos.ap-guangzhou.myqcloud.com/images/6662712fe7cd9de582fb1a8070c54c99.png)

Here we mainly take a front-end project as an example (a project created using umi)

```bash
mkdir myapp && cd myapp
pnpm dlx create-umi@latest
```

## 2. Talk about the basic commands of Docker

### 1. Common commands related to mirroring

```bash
# To download the mirror, first look for it from the local, did not go to the mirror, and finally did not go to the hub, if the label is not written, the default is latest

docker pull [image_name]:[image_tag]

# show all of images
docker image ls
docker images

# delete image file, -f force to delete
docker rmi [image_name][:Tag]
docker rmi [image_name1][:Tag1] [image_name2][:Tag2]    # delete muti images
docker rmi $(docker ps -a -q)    # delete all of images

# query the image name, --no-trunc displays the complete image description, --filter=stars=30 lists the images whose star is not less than the specified value, --filter=is-automated=true lists the images of the automatic build type
docker search [keyword]

# download the image, if the tag is not written, the default is latest, or you can add it yourself, for example: 3.2.0
docker pull [image_name1][:Tag]
```

### 2. Common commands related to containers

```bash
# list the running containers of this machine, -a lists all containers of this machine including the terminated container, -q silent mode only displays the container number, -l displays the most recently created container

docker container ls     
docker ps

# create new container
docker run [option] [container_name]

#  start container
docker start [container_id]/[container_name]

# restart container
docker restart [container_id]/[container_name]

docker stop [container_id]  # stop container
docker stop $(docker ps -a -q) # stop all of containers

# remove container by id
docker rm [container_id]
docker rm `docker ps -aq`    

# set the container to start automatically when docker starts
$ docker container update --restart=always [container_name]
```

I want to talk about `docker run`it `option`, because it is the most commonly used:

* `--name` specifies a name for the container;
* `-d` The container enters the background after starting and returns the container ID, that is, starts the daemon container;
* `-P` random port mapping;
* `-p` 80:8080 maps local port 80 to port 8080 of the container;
* `-i` runs the container in interactive mode, usually used together with -t;
* `-t` reassigns a pseudo-input terminal for the container, the shell of the container will be mapped to the current shell, and then the commands entered in the local window will be passed into the container, usually used together with -i;
* `--rm` automatically deletes container files after the container terminates;
* `--restart=always` set the container to start automatically;
* `-v` /xxx:/yyy mapping command, map the xxx directory of the local machine to the yyy directory in the container, that is to say, if the content in the xxx directory of the local machine is changed, the content in the yyy directory of the container will also change;



## 3. Write Dockerfile

`umi`Since the product will be placed `dist`under the directory after the build, we can write the following Dockerfile;

> Dockerfile is used to declare the steps of image execution; students who are not familiar with the following commands can [click to view this article (opens new window)](https://yeasy.gitbook.io/docker_practice/image/dockerfile/copy)

```
FROM nginx:latest # use nginx to base image
LABEL maintainer "your github email"
ADD ./dist /usr/share/nginx/html # put the product in the /usr/share/nginx/html directory of nginx
EXPOSE 80 # 
```

## 4. Write github action

Since only one private image is `hub.docker.io`currently supported, we will not consider using it for the time being; it is recommended that you use `github`the built-in image source [ghcr.io](ghcr.io)

**Preparatory work**

1. Go to https\://github.com/settings/tokens to generate a token, note that this token needs permission to read and write packages, please see [here for details (opens new window)](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)
2. Prepare the account number and password of your server to be deployed (the current page can use the secret key to log in, and the password is used here for now)
3. Think about your image name (here we take web-image as an example)

In `.github/workflows`the directory create a`publish-image.yml`

```yml
name: Publish Image

on:
  push: # push to the main branch for automatic release
    branches: ["main"]
    paths-ignore: # ignore some unnecessary files
      - ".gitignore"
      - "README.md"
      - ".vscode/**"
  pull_request:
    branches: ["main"]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: docker/login-action@v1
        with:
          registry: ghcr.io # declare mirror source
          username: ${{ github.actor }} # current github username
          password: ${{ secrets.HUB_GITHUB_TOKEN }} #  you need to go to https://github.com/settings/tokens to generate a token named token, note that this token requires permissions such as reading and writing packages
      - uses: actions/setup-node@v2
        with:
          node-version: "16.14"
      - uses: actions/cache@v2
        id: cache
        with:
          path: node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-
        # Runs a single command using the runners shell
      - name: pnpm install
        run: npm install -g pnpm
      - name: Install
        if: steps.cache.outputs.cache-hit != 'true'
        run:  pnpm i

      - name: Build
        run: npm run build
      - name: Show Dir
        run: ls

      - name: Build the  Docker image
        run:
          | # use the Dockerfile written in the previous step to build the image and publish it to the private warehouse; after the release is complete, you can go to https://github.com/your_github_name?tab=packages to view
          docker build . --file Dockerfile --tag ghcr.io/your_github_name/web-image:latest 
          docker push ghcr.io/your_github_name/web-image:latest
      - name: Update to Server
        uses: appleboy/ssh-action@v0.1.10
        with:
          host: ${{ secrets.SERVER_HOST }} # Server ip address; you need to go to the settings/secrets/actions of the warehouse to create
          username: ${{ secrets.SERVER_USER }} # server username
          password: ${{ secrets.SERVER_PWD }} # server password
          port: ${{ secrets.SERVER_PORT }} # server port
          script: | # Re-update the mirror and deploy
            docker stop web-image 
            docker rm web-image 
            docker login -u your_github_name -p your_github_token https://ghcr.io 
            docker pull ghcr.io/your_github_name/web-image:latest 
            docker run -dp 80:80  --restart=always --name web-image ghcr.io/your_github_name/web-image

        # The above uses port 80 to start, of course you can also change to the port you want
```

## 5. Private docker image

The private image we `github`used `ghcr`; of course, you can also create a private image based on docker/register; you can run the following command on your own server

```
# 1、download images
docker pull registry:2

# 2、run container 
$ docker run  -d --restart=always  -v /opt/registry:/var/lib/registry -p 5000:5000 --name myregistry registry:2
```

Then build the image locally and upload the image:

```


# privatization build
$ docker build . --file Dockerfile --tag server_ip_address:5000:web-image:latest

# privatization push

$ docker push server_ip_address:5000:web-image:latest

# Note that an error was reported when uploading the image：http: server gave HTTP response to HTTPS client

# 【Execute on the client side of docker push, not the private server】Solution 1：
# 1、edit /etc/docker/daemon.json，write in the file: (if your image is actually on linux/centos)

{ "insecure-registries":["server_ip_address:5000"] }

# 【Execute on the client of docker push, not a private server】 or solution 2 (if your image is on linux/centos)

$ sudo vim /usr/lib/systemd/system/docker.service
# and change content

ExecStart=/usr/bin/dockerd  --containerd=/run/containerd/containerd.sock --insecure-registry server_ip_address:5000

# 2、restart server and docker 

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
# push once
$ docker push server_ip_address:5000:web-image:latest
```

If you are using windows/mac, you can directly add it in the docker settings

```
{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "features": {
    "buildkit": true
  },
  "insecure-registries": ["server_ip_address:5000"]
}
```